Você está na página 1de 530

C# and Game Programming

C# and Game Programming:


A Beginner’s Guide
Second Edition

Salvatore A. Buono

CRC Press
(tf* Taylor &. Francis Group
Boca Raton London New York

CRC Press is an imprint of the


Taylor & Francis Group, an informa business
AN A K P E T E R S B O O K
CRC Press
Taylor & Francis Group
6000 Broken Sound Parkway NW, Suite 300
Boca Raton, FL 33487-2742
First issued in hardback 2019

© 2005 by Taylor & Francis Group, LLC


CRC Press is an imprint of Taylor & Francis Group, an Informa business

No claim to original U.S. Government works

ISBN-13: 978-1-56881-236-6 (pbk)


ISBN-13: 978-1-138-42810-2 (hbk)

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.

Visit the Taylor & Francis Web site at


http://www.taylorandfrancis.com

and the CRC Press Web site at


http://www.crcpress.com

Library of Congress Cataioging-in-Publication Data

Buono, Salvatore A., 1968-


C# and game programming : a beginner’s guide / Salvatore A. Buono. - 2nd ed.
p. cm.
ISBN 1-56881-236-1
1. C# [Computer program language] 2. Computer games—Programming. I. Title.

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.

M atthew Salvatore Buono, Born 9/28/03


Table of Contents

Preface xvii

PART ONE: Programming Basics 1

Chapter One: C# from the Beginning 3

An Overview of the C# Language.......................................................................... 3


A Little History on the Cs...................................................................................... 4
W hat is the Net Framework?..............................................................................5
Managed Code and Assemblies...........................................................................6
Algorithms.............................................................................................................7
The Net Compiler................................................................................................. 8
Compiling and Executing..................................................................................... 10
Comments.......................................................................................................... 15
Screen Output.................................................................................................... 16
The Newline Character.......................................................................................18
The WriteLine Command.................................................................................. 20
The Semicolon.................................................................................................... 22

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

Chapter Two: Branches, Loops, and Functions 59

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

PART TWO: Game Programming Basics 1 27

Chapter Three: Introducing DirectX_______________________ 1 2 9

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

Chapter Four: Arrays, Pointers and Strings 215


Arrays...............................................................................................................21 5
Declaring and Referencing Arrays...................................................................217
Assigning Values to A rrays............................................................................. 220
Passing Arrays to Functions............................................................................222
Multidimensional Arrays..................................................................................22 5
Three-Dimensional Arrays................................................................................228
Searching Arrays............................................................................................. 232
Dynamic Arrays in C # ......................................................................................235

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

Saving and Retrieving D ata.............................................................................. 287


Expanding Our Arsenal.....................................................................................288
Brainstorming..................................................................................................288
Battle Wave: The Heart of the Game.............................................................. 289
Game 5—Battle Tennis.................................................................................... 289
Adding Graphics...............................................................................................29 0
Input Devices: Keyboard, Joystick, and Mouse................................................295
The Properties of Sound...................................................................................297
Three-Dimensional Sound................................................................................ 299
Using Sound Effects.........................................................................................30 0
Changing Levels...............................................................................................303
Completing the Game...................................................................................... 30 4
Troubleshooting............................................................................................... 30 4
Things to Remember....................................................................................... 305
Questions......................................................................................................... 306

Chapter Five: Object-Oriented Oesign 309

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

The Keyword lock............................................................................................. 397


The Keyword param s...................................................................................... 398
The Keyword sealed.........................................................................................399
The Keyword stackalloc................................................................................... 4 0 0
Metafiles Defined............................................................................................. 4 0 0
Building Game Classes.................................................................................... 401
Game Classes—Animatedlmage.es................................................................ 401
Animation......................................................................................................... 40 3
Displaying......................................................................................................... 4 0 4
Adding Substance to Characters.................................................................... 40 5
Creating Infinite Space.....................................................................................4 0 9
Other Types of Deflection................................................................................. 40 9
Inheriting from Animatedlmage.es—Player.cs................................................. 4 1 0
Inheriting from Player.cs—PlayerlmageArray.cs.............................................. 411
Inheriting from PlayerlmageArray.cs-MultilmagePlayer.es...........................41 3
Inheriting from PlayerlmageArray.es—Shapes.cs............................................4 1 4
Inheriting from Shapes.cs—Patterns.es.......................................................... 41 8
GameState.es...................................................................................................4 2 0
GameTimer.es..................................................................................................42 2
TimedEvent.cs..................................................................................................4 2 4
Utils.es............................................................................................................. 42 5
Wall.es............................................................................................................. 42 7
Introducing D irect3D ....................................................................................... 4 2 9
Brainstorming..................................................................................................4 3 0
Game 6—Ground Assault................................................................................ 431
Brainstorming..................................................................................................431
Graphics........................................................................................................... 432
Game 7—Rat Racer.........................................................................................43 2
Adding Animation............................................................................................. 43 2
Brainstorming..................................................................................................43 2
Troubleshooting............................................................................................... 43 5
Assignments.................................................................................................... 4 3 5
Conclusion........................................................................................................ 4 3 5
Questions......................................................................................................... 43 5

XV
C# and Game Programming

Appendix A: Keywords/ Reserved Identifiers 437


Appendix B: Reserved Identifiers Defined 43 9
Appendix C: Accessors 47 3
Appendix D: Order of Precedence 475
Appendix E: Displaying Message Boxes 477
Appendix F: Graphics 483
Appendix G: Colors 489
Appendix H: Algorithms 491
Appendix I: Adding DirectX References 49 9

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.

How to Use this Book


W hen 1 designed this book, I knew it had to serve two purposes: The first being to teach the
C# language in a fun, yet practical, context, and the second to introduce the novice program ­
m er to the more advanced concepts of object-oriented programming and .Net design. I ac­
complished both of these tasks by first designing a traditional programming text and then
adding in several programming examples th at sim ulate the old arcade style games of the
late 1970s and early 1980s. While the games are enjoyable and do motivate study, their true
purpose is found in their collective relationship to object-oriented principles. As with the
game programming portions, the order of the traditional source coding is designed to em pha­
size an easy flow and a simple approach to programming. Nevertheless, do not interpret th at
to mean th a t this text won’t be a handful. The m aterial should take several m onths to
complete with its Base Class Libraries serving as an invaluable source for further study.

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.

About the CD-ROM


The com panion CD-ROM included w ith th is book covers the source code (program ­
m ing text) and several previously compiled program s, all labeled and listed in the
order discussed in the text. Each set of program s is placed in a folder title d a fter its
c h ap ter (as in C hap ter 1, C hapter 2, etc.). In addition, I have included an a s so rt­
m ent of games, all m eant to aid in your learn in g and productivity. To load the source
codes off the CD-ROM ju st follow th e in stru ctio n s listed on the next page.

1 Please check w ith tho se vendors fo r th e a p p ro p ria te com piler(s).

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).

2 The p ro g ra m s depicted in th is te x t w ere intended fo r use w ith M ic ro s o ft’s .N et com piler.


C# and Game Programming

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.

How to Read this Book


This book is w ritten for everyone w anting to learn the C# language in a fun yet practi­
cal context. The book is broken up to accommodate three skill levels.
Part 1: P rogram m ing B asics covers the most fundam ental portions, including pro­
gram m ing history, how to setup your compiler, and algorithms. It also introduces critical
m aterial on the .Net framework, data types, input and output commands, legacy coding,
the Base Class Library, comparisons and loops, switch statem ents, type casting, boxing
and unboxing, and method m anipulations (arguments, polymorphism, and recursion).
P art 2: G am e P rogram m in g B a sics also covers very basic concepts—nam ely
single and m ultidim ensional arrays, pointers (under unsafe mode), string functions,
and stream s—but eventually leads the reader out of the novice stage. O ther key topics
include an introduction to object-oriented programming, using Window’s applications for
graphics and sounds, and realtim e game program m ing techniques. Seasoned C/C++ pro­
gram m ers can usually jum p in a t this level, using the earlier portions as a convenient
point of reference.
P art 3: O bject-O riented P rogram m in g begins with structures, but quickly m i­
grates into classes and the principles behind object-oriented program ming. Fields, m eth­
ods, and operator overloading are discussed early on, w ith inheritance, virtual func­
tions, delegates, and exception handling expanding our capabilities. Here, we’ll also
expand upon the principles of the .Net environm ent, including reflection, threads, syn­
chronization, CLS (Common Language Specifications) complaints, language specifica­
tions, and a furth er study of the Base Class Library.
This book can also be used by anyone taking C# in a standard college course. Thus, the
text covers topics such as bubble sorting, search algorithm s, and most teachers’ favorite,
default settings (although I personally prefer using parenthetical expressions).
In addition to following the book from chapter to chapter, you could also reroute your
studies to include alternate paths or approaches. One such example would be to proceed
from C hapter 2 straight to C hapter 4, since the gaming portions m ight not interest you.
Alternatively, you could skip some of the more difficult gaming concepts listed in Chapters
3-5 and then retu rn to th a t m aterial after finishing the traditional studies. It is, however,

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.

Getting Help from the Author


Since this book is m eant to teach one of the v ast and often expanding C languages, I
felt th a t it was necessary to include a continuously updated e-m ail forum and in te rn et
new sletter, th a t is, a forum th a t will include any new or improved features, including
program m ing errors and ways to fix problems. I’d also like to encourage all beginner
program m ers by generating a list of web sites, source coding (including arcade style
clones), and any other new developm ents. To register for your FREE in te rn et new s­
le tte r, or to w rite in w ith a problem or re q u e st, p lease a d d re ss your em ail to
Plague@iwon.com.

The Student Perspective


This book was w ritten from the perspective of the student. Every attem pt was m ade to
move the reader along in a logical and progressive m anner. Nearly every keyword and
command has a working (live code) example, and when necessary, the reader is pre­
sented w ith a list of background inform ation and troubleshooting sections th a t are u su ­
ally covered by an instructor or gained in some previous program m ing language.
There are several sections th a t cover the secondary steps of program m ing such as
C# to Windows setups, compiler setups, and topics on game coding. The game coding,
while considered trivial by m any instructors, is one of the most effective ways of dem on­
strating C#’s object-oriented potential. Each new game is constructed w ith the in ten t of
maximizing the use of the coding studied in th a t chapter. The games, while e n te rta in ­
ing, also force the reader to press beyond simple logic and answ er questions th a t are not
staged or lim ited to simple text based outputs.
The chapters follow an alm ost evolutionary p a tte rn th a t begins w ith the basics of C#
and progresses through the techniques of structured, modular, and Object-Oriented Pro­
gram m ing (OOP), with the last section obviously concluding w ith the latest advances in
Microsoft’s .Net architecture. Both our text concepts and the games developed are p a rt of
th a t evolution, which prim arily defines which games can and will be developed w ith the
keywords and commands available.

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!”

About the Author


W hen I was a boy, I had a “TRS Color Computer.” It was hooked up to a TV set and had a
cassette drive. I used it to w rite sim ple text style gam es and AI driven chess program s.
A few years later, my m other bought me an Amiga 500 (a highpowered gaming computer).
I used it to w rite simple games like Tennis, Space Fighter, and R at Racer (all in the nam e
of education, I swear). Shortly after receiving th a t computer, I entered college. From there,
I earned two degrees, the first in M ath and the second in Engineering. Eventually I had to
sell th a t old Amiga and buy/build myself a newer IBM/Intel compatible computer. U pgrad­
ing th a t com puter actually turned into a career of sorts, leading first to online technical
support and eventually to game program ming. After graduating, I tu rn ed my talents
toward writing, or more specifically, toward technical writing, but you should have guessed
th at. I also m anaged to get m arried, buy a little house, win a few Jiu-jitsu tournam ents,
and well, there is th a t whole gaining superpowers thing. As for my TRS Color Computer,
I removed its plug and gave it to my nephew as a toy typew riter—ju st imagine the day
when the Pentium IV becomes th a t outdated.

There’s a mouse on the desk, there’s a mouse on the desk...


I’m sure there’s been a mistake here, does anyone know why there’s a mouse on my desk?

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.

An Overview of the C# Language


C# is a high- or mid-level program m ing language (and ju st in case you didn’t know, a
program m ing language is the collection of words, phrases, and syntax rules used to
communicate with the computer). Although there are m any high-level program m ing lan ­
guages (BASIC, JAVA, FORTRAN, Pascal, Lisp, ADA, Modula-2 and Logo), few have

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.

A Little History on the Cs


C was developed in the 1970s by Dennis Ritchie while he worked at AT&T Bell Laborato­
ries. Before C, there was a language called B developed by Ken Thompson. While there was
an A language, B was actually developed from Basic Combined Program m ing Language
(BCPL), which was developed from a combination of two other languages, nam ely CPL
and Algol60. C++s object-oriented portions are attributed to still another language known
as Simula67. CPL begot BCPL; BCPL begot B; B begot C; C begot C++; and C++ begot C#.
In 1979, Bjarne Stroustrup (also at AT&T Bell Laboratories) developed the first version of
C++ to be an enhanced version of the C language (initially referred to as C with classes).
C++ was significantly enhanced with the addition of the Standard Template Library (STL)
developed by Alexander Stepanov and Meng Lee at Hewlett-Packard. The STL was based
heavily on previous work done by both Stepanov and Musser, from Rensselaer Polytechnic
Institute.
Both C and C++ spread quickly in power and use, but eventually all the added
features and expansions lead to incom patibilities and frustrations. Two standards were
created, first w ith the Am erican N ational S tandards In stitu te (ANSI) C stan d ard of
1983, and then the Am erican N ational Standards for System s Inform ation and In te rn a ­
tional S tandards O rganization (ISO) C/C++ stan d ard s of 1998 (Note: C was also u p ­
dated in this second standard). The 1998 ANSI/ISO stan d ard is generally referred to as
Native C++, while Microsoft’s .Net Extensions are known as M anaged C++. C# w as also
standardized w ith its first release under w hat is known as the 2001/2002 ECMA certi­
fied standard.
C# was developed by a team of Microsoft program m ers led by chief architect Anders
Hejlsberg. It is intended to supplem ent the developm ent of applications required for
both stream users and in tra n et/in tern e t program m ers alike. C# is definitely one of the
most sophisticated languages ever developed, and sim ilar to the entire .Net architecture,
it will alter the way program m ers th in k about program m ing for m any years to come.

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.

As you can see, C# evolved from the simpler languages.


Hey, I thought it was created by a programmer.

W h a t is the .Net Framework?


The .Net fram ew ork is a m ultitasking, class-based program m ing library and interface
th a t allows for both the interoperable exchange and execution of data. As a library, the
.Net base classes are as powerful as the traditional Windows API function set, but have
the added advantage of being completely object-oriented. Object-oriented program m ing
(as explained throughout th is book) is a practical m ethod used to develop program s th a t
promotes both the reusability and reliability of code. The .Net runtim e (also known as the
Common Language Runtim e or CLR) serves as a shell or interm ediate environm ent th a t
assists the operating system w ith program execution(s).
The .Net fram ew ork also allows for program interoperability, requiring a Common
Type System (CTS) governed through the Interm ediate Language commonly known as
Microsoft's Interm ediate Language (MSIL) and/or the Common Interm ediate Language
(CIL). Interm ediate Language should not be confused w ith J a v a ’s in terp reted byte-type
coding, which does not have the ability to be compiled. Microsoft has also developed a
secondary type of compilation known as JIT (just in time) compilations. U nder JIT,
program s are not only installed into our system s, but the code is optim ized for the
processor. In addition, J IT compilation shortcuts the basic sta rtu p tim e by lim iting com­
pilation to only the required portions, which also improves overall performance.
The .Net architecture also offers some interesting advantages, including memory m an­
agement (also known as garbage collection) and zero-impact installation. Garbage collection
(stemming from Java) is a systematic approach to eliminating previously allocated memory

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.

Managed Code and Assemblies


M anaged code is the term used to define the coding im plem ented under the .Net fram e­
work, while the term s native and unm anaged code are used to indicate coding th a t
bypasses this new architecture and is im plem ented directly through the Windows API.
Assemblies are u nits in which m anaged coding is stored. Assemblies also contain infor­
m ation packets referred to as metadata: m etadata packets keep track of an assem bly’s
contents including its objects, m ethods, and types. Shared assem blies are stored in a
central area referred to as the assem bly’s cache. M etadata packets are stored in an area
inside these assem blies known as the manifest.

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).

E xam p le 1.1. A b b rev ia ted A lg o rith m for P a d d le T en n is.

1. C reate a viable Windows handle accessible through the


Windows console settings.
2. W rite a function to draw the p lay er’s characters.
3. Include a function th a t paints/clears the screen.
4. Define most of the variables as a m em ber of a single class, w ith
th e m ost notable exception being the color settings.
5. Set the variables/m em ber, setting the ball to a random
direction.
6. Create a while-loop that ends when the gam e ends.

Inside the while loop


7. W rite a function th a t rem oves our resid u al im ages using a
com bination of calls to blank characters and/or a full-blown
clear screen function.
8. Set the colors: Since these colors never change, th is can be
done from either the do-while or in tern al while loop.
9. D isplay the players, ball, and the scores (0 to 0 as we start).
C# and Game Programming

10. W rite a function th a t reads the players input from the


keyboard.
11. W rite a function to propel the ball.
12. W rite a function to lim it th e area in which the players can
traverse.
13. Include sounds when the ball bounces
14. Check to see if the ball and player have collided (see Collision
Detection: The Ball in Motion). The ball should bounce off the
player.
15. If the ball gets to the end of the screen and the player is not
there, give the other player a point. Now, reset the ball.
16. R epeat the loop u n til eith e r player scores a specified num ber.
17. Ask player(s) if they w ant to play again. Rem em ber a good
game loop should alw ays allow the player(s) the option of
playing again.
18. E nd or rep eat game.

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.

The .Net Compiler


A tra d itio n a l com piler tra n s la te s higher-level languages into the m achine’s own la n ­
guage, ap p ro p riately nam ed M achine Language. P rogram m ers developed higher-
level languages such as C and C++ to bridge th e gap betw een h u m an languages and
th e c o m p u ter’s b in ary code of ones and zeroes. As difficult as C# and o th er high-
level languages seem, th e ir difficulty doesn’t com pare to the com plexity of try in g to

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.).

Common Language Specifications: While the .Net framework is designed


to promote language interoperability, the use of the C# language does not
guarantee that level of interaction. We can, however, make C# CLS compliant
with what are generally only minor adjustments to our overall method of
programming. For example, we must adjust our programs to avoid the use of
unsafe coding (specifically, pointer notation). In addition, we must avoid the
use of some data types, namely s b y te , ushor t , u i n t , and ulong. Finally,
we’ll have to restrict our naming practices to avoid conflicts with Visual Basic’s
inability to distinguish between upper and lower case settings (e.g., Cl as si
and classl).

9
C# and Game Programming

Compiling and Executing


While the theories of proper compilation and execution were outlined in the previous sec­
tions, we still haven’t established a practical method for the implem entation of our applica­
tions. Before our programs can be executed either with or without an external .Net environ­
ment, they m ust first go through a process known as compilation. Hence, to start, you’ll
need a computer program known as a compiler. I recommend Microsoft’s C# .Net in any of
its packaged standards (trial, standard, professional, or enterprise). I’ve also included simple
step-by-step instructions on how to set up those compilers.

Quick Setup for Microsoft Visual C# .NET:


1. M ake sure your compiler is installed and w orking properly.
2. Load and activate the C# compiler. Close any nonessential windows.
3. From the “File” menu, select “New” and then ‘Project” (see Screen Shot 1.1).

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 — :•..

4. At th is point, a second window should open. Select the icon


labeled “Console Application” (see Screen Shot 1.2).

10
Chapter 1: C# from the Beginning

&le £d* Sew Prelect £>ebug Xocfe gfndow Help

g l* § £ f i* « C P * ' ^ ^ - » - & n* * Debug

* * © © < & v*:/drfaulthto *

*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

Console Windows Empty Project


Appficaticn zl
A project for creabrsj a r a i r n w i d ^ ijspicaBon

Name: | CcrsoSeAppfc<sU>ri2

Location: | Qi£«ocumer*s arid 5ettingsVPIaque\Hy Oocuments^ysu '■>{


Screen
C Add to Solution <♦“ Close Solution
Shot
1 .2 .

3 Task 1st a Output!


Zjr

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.

5. Typing in your C# source coding is as sim ple as entering text into


a word processor. J u s t m ake sure th a t the larger window to the
right is active. Note th a t an active window is usually m arked by
a blinking cursor.

11
C# and Game Programming

E xam p le 1.2. Our fir st program .


using System;

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

f t TODO: Add cod* to start application here Screen


Shot
1.5.

“3
) ( a ile d , 0 skipped
.3

3T«kU',t Q Octa*!
B»Jd succeeded Coh ..ws

13
C# and Game Programming

jr C i Pocumenls and Settings Plague My Document* Visual Studio


[Press any key to continue,,, •

Screen
Shot
1.6

hi

Example 1.2 Explained


C# uses several d a ta types, including integers, real num bers, c h aracters, and void.
Void, for all practical purposes, m eans w ithout a type. Moreover, since the m ain func­
tion doesn’t u sually req u ire a d a ta type, void is the sim plest to use. D ata types such
as int, float, double, char, and void are explained in d etail la te r in th is ch a p ­
ter.
The com m ands static void Main (string [] args) and static void
Main ( ) are m ost commonly referred to w hen in d icatin g the m ain m ethod. The
m ain m ethod serves as the controller to the rest of the program . In th ese beginning
stages, we’ll w rite all com m ands inside of the m ain m ethod, but later, as our p ro ­
gram s advance, w e’ll m ig rate to o th er subprogram s th a t will do specific task s. The
m ain m ethod will th e n serve as a controller to these subprogram s. W riting pro ­
gram s in th is m an n er is ak in to an older m ethod of program m ing know n as stru c ­
tured p ro g ra m m in g , which is a very im p o rtan t p a rt of both C and N ative C++ th a t
the object-oriented approach will eventually surpass.
The opening and closing braces (also known as a block) sim ply m ark the b egin­
ning and ending of the program 's environm ent. The com puter recognizes these sym ­
bols as m ark ers tellin g it w here to s ta rt and w here to end. W ithout such m ark ers,
program s would not know which coding belonged to which m ethod. Each block, then,
indicates a subenvironm ent, w hereas the nam espace's exterior block re p re se n ts the
global environm ent (Note: Com m ents are explained in the next section).

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.

E xam p le 1.3. S in g le lin e com m en ts.


using System;

namespace Chapterl {
class Classl {
static void Main ( ) { // Main method
// Begin executable statements
} // End main method
}
}

E xam p le 1.4. M u ltip le lin e com m en ts.

/* Longer comments (comments spanning two lines or more) are


* often set aside with these special markers.
* Comments are ignored by the compiler and thus
* do not affect the program's speed. */
using System;

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).

E xam p le 1.5. XML com m an d s.

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!");

The command th a t moves the cursor to the next line is:


C o n s o l e .Write ("\n");

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

static void Main () {


C o n s o l e .Write ("Hello, Progra mm er .\n");
C o n s o l e .WriteLine ("How are you today?");
}
}
}

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

\? L iteral quotation m ark

V Single quotation m ark

\” Double quotation m ark

\\ Backslash

T able 1.1. Escape sequences.

The Newline Character


The symbols backslash and n (\n ) were used in the previous section inside a p air of
quotes, but they were not displayed to the screen w ith the words “Game Over” or “Hello,
World!” This combination, known as the newline character, serves as a m arker telling
the program when to move to the next line. The newline character is one of m any special­
ized characters referred to as escape sequences (see Exam ple 1.9). For a complete list of
escape sequences, see Table 1.1.

18
Chapter 1: C# from the Beginning

E xam ple 1.9. The n e w lin e ch aracter.

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.

E xam p le 1.10. M ore p r a c tic e w ith th e n e w lin e ch a ra cter.


/* more practice with the newline character */
using System;

namespace Chapterl {
class Classl {
static void Main() { //Begin main
C o n s o l e .Write ("This is line 1\ n" );

C o n s o l e .Write ("This is line 2 \ n ") ;


Console.Write ("This is line 3");
C o n s o l e .Write ("This is still line 3\ nM
C o n s o l e .Write ("This is line 4\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.

E xam p le 1.11. D isa b lin g th e e sc a p e se q u e n c e s u sin g th e @ sym b ol.


using System;

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


An alternative to retu rn in g one’s cursor position w ith the newline character is to re ­
place it w ith the WriteLine command.
C o n s o l e .WriteLine ("");

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).

E xam p le 1.12. The WriteLine com m and.


using System;

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).

E xam p le 1.13. T he WriteLine com m an d co n tin u ed .


using System;

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.

E xam p le 1.14. R e p la c in g n e w lin e c h a r a c te r s w ith WriteLine.


using System;

namespace Chapterl {
class Classl {
static void Main() { // Begin main

21
C# and Game Programming

Co n s o l e .W r i t e L i n e ("This is line 1");


C o n s o l e .W r i t e L i n e ("This is line 2");
C o n s o l e .W r i t e ("This is line 3");
C o n s o l e .WriteLine (" This is still line 3");
C o n s o l e .W r i t e L i n e ("This is line 4");

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

Included files (listed as #include <filename>) were simple comm uniques th a t


allowed the addition of specialized files to program s. In effect, they m ean “include this,”
w ith “th is” being whichever header file followed. The pound symbol was always placed
in front of the included statem ent, which allowed the compiler to identify it. The files
accessed were essentially little side program s th a t usually did som ething useful like
p rin t words to the screen, or even to the printer. Included statem ents and the functions
th a t they linked to our program s were essential to program m ing in C and C++. How­
ever, this is no longer the case, since C# h as elim inated the need for such references and
instead uses an object-oriented approach. This approach is actually w hat defines the
.Net architecture and is w hat is m eant by the Base Class Libraries (not to worry, all of
these topics will be explained in g reater detail late r in this text).

Note: For C++ Programmers:


While it may appear that the using and #include statem ents are of similar
design, that assumption is incorrect. In fact, the key purpose of the using
feature is merely to allow for abbreviated class name references.

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

1. Variables consist of only letters, numbers, and the underscore symbol.


2. Variables m ust alw ays s ta rt w ith a lette r or the underscore
symbol. (Note: U nderscores and coded prefixes are usually
reserved by large projects and companies).
3. Variables cannot have the sam e nam e as a reserved word or
keyword (see Table 1.2 for a complete list of keywords). It is
possible to use the special @ symbol to override th is lim itation as
in @char, but th is is usually unnecessary.

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

abstract decimal float namespace return try

as default for new sbtye type of

base delegate foreach null sealed uint

bool do goto object short ufong

break double if operator size of unchecked

byte else implicit out stackalloc unsafe

case enum in override static ushort

catch event int pa rams string using

char explicit interface private struct virtua 1

checked extern internal protected switch void

class false is public this volatile

const finally lock readonly throw while

continue fixed long ref true

T able 1.2. Keywords.

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

E xam ple 1.15. N am in g v a ria b les.

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.

Other possible variable names include:


- Number integer whole_number computer_data
- Lives game_lives deaths bombs_on_ship

Declaring Variables and the Integer Data Types


There are five basic d a ta types: integer (int), float, double, character (char),
and void. Each of th ese h a s a specific purpose, b u t to apply th ese v a ria b le s properly
we m ust first le a rn how to declare them . An in te g e r is any positive or negative whole
nu m b er (see Exam ple 1.16). To declare an integer, use th e keyw ord int, followed by
th e v a ria b le nam e and a sem icolon (R em em ber th e sem icolon ends th e com m and
line.). We can declare d a ta ty p es u sin g e ith e r th e comm on m ethod or by ex p ressly
sta tin g th e ir CTS type. We can also declare m ultiple v ariables in any one program by
e ith e r re p e a tin g th e int keyw ord or ad ding a d d itio n a l v a ria b le s to th e line as is
im plied by th e use of th e comm a o p e ra to r (see E xam ples 1.17 and 1.18).

E xam p le 1.16. A n u m b er lin e o f in te g e r s.

-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

E xam p le 1.17. D e c la rin g v a r ia b le s u sin g com m on m eth od .

using System;

namespace Chapterl {
class Classl {
static void Main() {
// these variable were declared using the data type integer
int Numberl, Number2;

Numberl = 1; // Their assignment values both equal one.


Number2 = 1;

// And, they're both displayed using the WriteLine function.


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");

E xam p le 1.18. D e c la r in g v a r ia b le s u sin g th e CTS typ e.

using System;

namespace Chapterl {
class Classl {
static void Main() {
System.Int32 Numberl, Number2;

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 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).

E xam p le 1.19. U sin g d ata ty p e s u lo n g /lo n g and u s h o r t / s h o r t .

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).

The Data Types f l o a t and d o u b le


The d a ta types float and double are both floating point d a ta types, and th u s can be
explained together. Floating point arith m etic allows higher precision in calculations.
Some floating point values are shown in Exam ple 1.20.

28
Chapter /\ : C# from the Beginning

E xam p le 1.20. F lo a tin g p o in t v a lu es.

1.0 2.5 5.15


7.146 18.001 178.01

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.

E xam p le 1.21. U sin g d a ta ty p e f l o a t .

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

C on s o l e .W r i t e L i n e ("The first number is " + Numberl


+ "\nThe second number is " + Number2 + "\n");

E xam p le 1.22. U sin g d a ta ty p e d ou b le.

using System;

namespace Chapterl {
class Classl {
static void Main() {
double Numberl, Number2;

29
C# and Game Programming

Numberl = 1.0;
Number2 = 1.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 Data Type d e c im a l


In addition to the basic d ata types, there are also several expanded d ata types (including
the predefined integer types listed earlier and several advanced types th a t we’ll hold off on
until later). This section introduces probably the most obvious of the floating point values,
the decimal.
The decimal is, of course, used to calculate m onetary equations th a t bring the high­
est level of accuracy to the dollar am ount (see Exam ple 1.23). Note: Conversion from
literal constants to the decim al data type require the M symbol to indicate a decimal
am ount = 1.50M.

E xam p le 1.23. U sin g da ta ty p e d e c im a l.

using System;

namespace Chapterl {
class Classl {
static void Main() {
decimal Numberl, Number2;
Numberl = 1.0M;
Number2 = 1.1m;

C o n s ol e.W r i t e L i n e ("The first number is " + Numberl


+ "\nThe second number is " + Number2 + "\n");

30
Chapter 1: C# from the Beginning

The Data Types character and string


The character (char) and string d a ta types are declared and assigned in the sam e
m an n er as the num eric variables, the m ain difference being th a t they allow for the
storage of characters ra th e r th a n num eric inform ation. Technically, num bers are also
included in th is list of characters, b u t th e ir values are not equivalent to th e ir num eric
counterparts. C h aracter variables are declared using the keyword char, and can be
assigned through u ser in p u t and/or as a p a rt of a declaration/assignm ent. They are
only capable of holding a single c h aracter value, and are assigned using single q u o ta­
tion m arks.
Strings, in contrast, allow for m ultiple c h aracter storage. A host of words, or
sentences, can be placed inside of a single strin g variable. Strings can also tak e in p u t
from outside sources, including direct input, stored files, etc. They are assigned using
double quotation m arks (see Exam ple 1.24). Traditionally, the c h aracter d a ta type
consum ed the sm allest am ount of system RAM (8 bits); however, th is changed w ith
the introduction of the new Unicode sta n d a rd (16 bits). The change rep resen ts a move
to a universal ch aracter base th a t includes m ost of the w orld’s languages, which is, of
course, an im p o rtan t p a rt of in te rn atio n a l commerce (Unicode is explained in more
detail in C hapter 3).

E xam p le 1.24. The c h a r a c te r an d s t r i n g d a ta ty p es.

using System;

namespace Chapterl {
class Classl {
static void Main() {
char Symbol;
string Sentence;
Symbol = 1A ';
Sentence = "This is a string.";

Cons ol e.W r i t e L i n e ("The first letter in the alphabet is "


+ Symbol + ".");
C on so le .W r i t e L i n e (Sentence);
}
}
}

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.”

Names CTS Type Description Approximate Range


Sbyte System.SByte 8-bit signed integer -128 to 127
Short System.lnt16 16-bit signed integer -32768 to 32767
Int System.lnt32 32-bit signed integer -2,147,483,648 to
2,147,483,647
Long System.Int64 64-bit signed integer -9223372036854775808
to 9223372036854775807
Byte System. Byte 8-bit unsigned integer 0 to 255
Ushort System.Ulnt16 16-bit unsigned 0 to 65,535
integer
Uint System.Ulnt32 32-bit unsigned 0 to 4,294,967,295
integer
Ulong System.Ulnt64 64-bit unsigned Oto
integer 18,446,744,073,709,551,6
15
Float System.Single 32-bit single precision ±1.5x10“* to ±3.4x10^
floating-point
Double System. Double 64-bit double ±5.0 x 10'32* to ±1.7 x
precision floating­ 10308
point
decimal System. Decimal 128-bit high precision ±1.0 x 1o e to ±7.9 x 10*a
decimal notation
Char System.Char 16-bit Unicode N/A
character
String System.String Unicode character N/A
string
Bool System.Boolean true & false values N/A
Object System.Object Type root N/A

T able 1.3. A pproxim ate storage capacities.

32
Chapter 1: C# from the Beginning

Keywords sizeof and unsafe


As with C++, C# can use the s i z e o f keyword to gather information pertaining to the size
of data types. Unfortunately, this also requires the use of a secondary command, u n s a fe ,
which is used to m ark the unsafe nature of th a t code. The practicality of using such coding
is limited, considering th a t it takes us out of the .Net environm ent and puts us back in the
anarchical world of Windows API. There are, however, legitim ate reasons for reverting to
th a t standard; one example is backward compatibility, and another is performance issues.
The steps to enable u n s a f e mode, as well as a simple s i z e o f program , are shown in
Example 1.25).

E xam p le 1.25. Sizeof and unsafe m ode.


using System;

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));

Enabling unsafe mode in C#


Once a project is loaded into the .Net compiler, it becomes a simple m atter of altering th a t
project’s build configuration to enable unsafe mode.

1. From the folder labeled “View,” select the file titled “Solution
Explorer” (see Screen Shot 1.7).

33
C# and Game Programming

CoosoleAppllcation? - Microsoft Visual C#.NET [design] - Classl .<

m e* S&
indow tie!
[J fi5>eo A,
sp*m OpegWith...

X# Solution Explorer Ctrt+Al+L

; jf^Con 35$ OassVtew Ctrt+SNft+C


”3 (^♦M
ai^sW
rtflC]«r0s>
% Server Explorer Ctrt+Ak+S
> " ♦ sizeof (ushortsj) ?
m gesource View Ctrl+Shtft+€ > * ♦ sizeof (shore));
Properties ggndow F4 ' + sizeof(uint));
er
+ sizeof(int));
X Toofcos Ctrl+Ak+X
* " + s iz e o f( u lo n g } ) ;
Screen m PencSng Chedcins ♦ sizeof (long));
WebBrowser ► ' + s i z e o f (fioet)) ;
Shot " + s izeof(double));
Cthgr Windows ►
1 * ♦ sizeof (<l*ci»ai));
1.7 Show Tasks ►
loefcars »

o FvP Screen SNft+Alt+Eflter :

& Navigate Backward CWt~

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>

B Tasklst j3 Output j f t Search Resits for /unsafe j

2. A second side window will open—m ake sure to highlight the


project ra th e r th a n the file nam e. Select “Properties,” the th ird
icon depicted in th a t sm aller window (see Screen Shot 1.8).

ConsaleApplicatkm? * Microsoft Visual C # .NET [design} Classl .cs

0te gd* fe w firojecl gy«d fcebug loots Window betp

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));

Screen Console.WriteLine("Float • » + sizeof(float));


Console.WriteLine("Double * " ♦ sizeof(double));

Shot Console.WriteLine("Decimal ■ " + siseof(decimal));


) >>
1.8

Task 1s t - 1 BuM error task shown (Htered)

Click here to add a new t « i


Program 'C:\Docuroerts and Sethngs\Ptague\My Do.

2) Tasklist I 3 f t ~

34
Chapter 1: C# from the Beginning

3. Now go to the listing labeled “Configuration Properties.” Select


“Build” from th a t sublist and click on th e “F alse” value under
“Allow U nsafe Code Blocks.” From there, an arrow will appear—
use it to select the “True” setting, press “Apply,” and th en “OK” to
finish (see Screen Shot 1.9).

*0te W* Eroject &ufW fcebog look Window belp

TLVw ..... ":


Mm ►

j £onfiguration; |^tk«<Do6ug)~ 3 ... ”3 Cgnfiguration Manager...

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

3 Tasklist j 3 o >SS? iicu >• - - v -(-.safi-


Ready

The Data Type v o id


As previously mentioned, void is a data type th at holds no data. It thus serves the purpose
of telhng the compiler th at a variable or returning function requires no data, which is logical
since the ending of the m ain function is also the ending of the program, and there would be
no program to receive information. The d ata type void is also most commonly associated
with user-defined functions th at use reference variables (explained in Chapter 2) and gener­
alized pointer-variables (explained in Chapter 4). Unlike the other data types, void does not
take a position in memory. Therefore, we don’t need to m easure its size in bytes.

35
C# and Game Programming

Assignment Statem ents


One other aspect of the above exam ples rem ains to be explained, namely, th e equal sign
(also known as the assignm ent operator). Quite obviously, using an equal sign m eans to
m ake the variable equal to w hatever num ber we assign, and is therefore known as an
assignm ent statement. This works equally well for assigning a variable to a literal con­
s ta n t or a referenced variable (as dem onstrated in Exam ple 1.26).

E xam p le 1.26. U sin g th e eq u a l sig n a ssig n m e n t op erator.


number_shown = x + 1;
// Arithmetic will be explained later in this chapter

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).

E xam p le 1.27. C om piler w a r n in g r e su ltin g from an u n d efin e d va ria b le.

- 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 .

// variable referenced without being assigned a value.

Type Compatibility: Implicit Conversions


Before we begin to combine num bers in the form of equations, we have to m ake sure th a t
their data types are compatible. Numeric data types, as you remember, were byte, short,
int, long, float, double, and decimal. The best way to calculate and assign these
d ata types is to use th eir m atching d a ta types (for example; short to short, float to float,

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

numeric symbol (#) as a placeholder, as in Console.WriteLine (“{0.#.00}”, variable); (for further


examples, see the Arithmetic section).

String
Description
Format

C Currency (local)

D Decimal (decimal point)

E Exponential (Scientific Notation)

F Fixed point

G General (E or F, to reduce space)

N Number (inserts commas, e.g., 1,313.02)

P Percent

X Hexadecimal

T able 1.4. Commands for form atting strings.

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.

E xam ple 1.28. In teg e r a d d itio n .

using System;

namespace Chapterl {
class Classl {
static void Main() {

38
Chapter 1: C# from the Beginning

int numberl, number2, total; // these are my variables


numberl = 5;
number2 = 2; // did you notice they're both integers?
total = numberl + number2;

C o n s o l e .W r i t e L i n e ("{0} + {1} = {2} ",


numberl, number2, total);
}
}
}

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.

E xam p le 1.29. In te g e r su b tra ctio n .

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

Console .W ri te Li ne ( " {0 ,3} \ n - {1 , 3 } \ n — \ n {2,3}",


numberl, number2, total );
Console.WriteLine("\n {0,3:D } \ n - {1,3:D}\n \n {2,3:D}",
numberl, number2, tot al );
C onso le .W ri te Li ne ("\n {0,3:X }\ n - {1,3:X }\n \n {2,3:X}",
numberl, number2, total);

To m ultiply and divide, use the asterisk (*) and the forw ard slash (/), respectively.

E xam p le 1.30. M u ltip lic a tio n w ith d ata ty p e f l o a t .

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 */

C o n s o l e .WriteLine (" {0,3:C2}\nx { l , 3 : F } \ n ---- \n {2,3:C2}",


numberl, number2, t ot al );
}
}
}

E xam p le 1.31. D iv isio n w ith d a ta ty p e d o u b le .

using System;

namespace Chapterl {
class Classl {

40
Chapter 1: C# from the Beginning

static void Main() {


double numberl, number2, total;
numberl = 5.0;
number2 = 2.0;
total = numberl / number2; /* 5 divided by 2 */

Console.WriteLine (" {0,3:E}\n/ { l , 3 : E } \ n ---- \n {2,3:E }",


numberl, number2, tota l) ;
Console.WriteLine (M\n {0,3:F}\n/ {l,3:F}\n \n {2,3:F}",
numberl, number2, total);
Console.WriteLine ("\n {0,3:G}\n/ { l , 3 : G } \ n ---\n {2,3:G}",
numberl, number2, total);

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).

E xam p le 1.32. O rder o f o p e r a tio n s 1.

Total = numberl * number2 + numberl;


15 = 5 * 2 + 5

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.

E xam p le 1.33. O rder o f o p e r a tio n s 2.

Total = numberl * (number2 + numbe rl );


35 = 5 * ( 2 + 5 )

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.

E xam p le 1.34. O rder o f o p e r a tio n s 3.

Total = numberl * number2 / numberl + number2 - numberl;


By order of operations: 5 * 2 / 5 + 2 - 5 = - l

E xam p le 1.35. O rder o f o p e r a tio n s 4.

Total = ((numberl * n u mb er 2)/number1) + number2 - numberl;


By order of parentheses: ((5 * 2) /5) + 2 - 5 = -1

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 .

E xam p le 1.36. The r e m a in d er sym bol.

Total = numberl % number2;


// the remainder of 5 divided by 2 is 1.

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).

E xam ple 1.37. The r em a in d er sym b ol w ith d ata ty p e in t e g e r .


using System;
namespace Chapterl {

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) ;

double percent, numl = 5.0, num2 = 2.0;


percent = num2 / numl;
Console.WriteLine("\n{0} is {l,0:P} of {2}",
num2, percent, n u m l ) ;
}
}
}

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.

Function Symbol Written as

1. Addition + total = numberl + number2;

2. Subtraction - total = numberl - num ber-

3. Multiplication * total = numberl * num ber-

4. Division / total = numberl / n um ber-

5. Remainder % total = numberl % number2;

T able 1.5. A rithm etic O perators.

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.

E xam ple 1.38. The R ead com m and.

using System;

namespace Chapterl {
class Classl {
static void Main() {
char character;
int integer;

C o n s o l e .W r i t e L i n e ("Enter a number here: " ) ;


integer = C o n s o l e .R e a d ();
character = (char) integer;
C o n s o l e .W r i t e L i n e ("And the number you entered is "
+ character);

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;

C o n s o l e .W r i t e L i n e ("Enter a number here: ");


convert = C o n s o l e .R e a d L i n e ();

C ons ol e. Wr it eL in e("Enter your name here: ");


Name = C o n s o l e .R e a d L i n e ();

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

Exam ple 1.40. D eclaring and in itia lizin g variables.

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);
}
}

Access Modifiers: constant, Readonly, and volatile


We can also sim ultaneously declare and initialize variables using the variable type
constant. A constant variable cannot change its value after it has been specified (this
is also true for the readonly modifier). Declaring a constant variable is sim ilar to our
last example, but w ith the added keyword const, which, of course, stands for constant.
Adding the keyword const notifies the compiler of its unchanging n a tu re and allows it
to optimize strange space for th a t value (see Exam ple 1.41).

E xam p le 1.41. D e c la rin g c o n sta n t v a ria b les.

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

Exam ple 1.42. C onstant variables o f various data types.

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!";

C o n s o l e .W r i t e L i n e ("This is a constant of type integer "


+ n u mb er l);
C o n s o l e .W r i t e L i n e ("This is a constant of type float "
+ numb er 2) ;
C o n s o l e .W r i t e L i n e ("This is a constant of type double "
+ number3);
C o n s o l e .W r i t e L i n e ("This is a constant of type char "
+ symboll);
Console.WriteLine(sentence);
}
}
}

Readonly is also a constant d ata type used as p a rt of a class reference (declared as a


field—see the M ethods section in C hapter 5); it is assignable a t only one point in the
program and then acts as a constant. In contrast, the keyword volatile (also addressed
in C hapter 5) expresses th a t the variable it precedes will change dram atically. For ex­
ample, th a t value m ay be altered by the system ’s clock, or used to pass data to a compo­
nent in hardw are. In eith er case, foregoing the volatile comm and will result in the
compiler autom atically lim iting th a t variable (this is done to optimize the program ’s per­
formance). Thus, in order to keep a variable’s access open to m any possibilities, we’ll need
to insert the volatile command before such variables (see Example 1.43).

E xam p le 1.43. Readonly and volatile.


namespace Chapterl {
class Classl {
public readonly double variable2 = 3.14159;

47
C# and Game Programming

public volatile char variable3 = 'A';

static void Main () {


/* This is a do nothing program */
}

#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.

Incrementing and Decrementing Operators


The increm enting (++) and decrem enting (— ) operators increase and decrease their vari­
ables by one num eric value, respectively. This holds tru e for all num eric d a ta types, in ­
cluding the standard integer, floating point, or decimal references (character information
is handled differently). The operators can be used in either postfix mode (x++) or prefix
mode (++x). Prefix mode refers to a calculation th a t m ust occur before a variable is
accessed by a secondary equation, w hereas postfix mode allows for th a t variable to be read,
equated, and then altered after the completion of the equation. There are, of course, advan­
tages to each type, and the la tte r explains the pun C++. Use Exam ple 1.44 to test these
operators. You should revise the example using several of the other numeric data types, as
well as both postfix and prefix modes.

E xam p le 1.44. In c r e m e n tin g o p era to rs I.

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++;

C o n s o l e .W r i t e L i n e ("The number is " + n umber++); // 2


Co n s o l e .W r i t e L i n e ("The number is " + number); // 3

E xam p le 1.45. I n c r e m e n tin g o p e r a to r s II.

using System;

namespace Chapterl {
class Classl {
static void Main(string [] args) {
int number = 1;
n u m be r+ +;

C o n s o l e .W r i t e L i n e ("The number is " + ++number); // 3


C o n s o l e .W r i t e L i n e ("The number is " + number); // 3

Type Safety versus Metonym Data Types


A m etonym ic expression is a nam e or p h rase used to identify an object or person th a t
goes beyond th e ir basic description or th a t of th e ir official designation. This could
m ean giving a pet nam e to a car or referring to a friend by th e ir screen nam e. In eith er
case, you are ju st identifying the person, place, or thing w ith an a lte rn a te nam e. C and
C++ use th e keyw ord typedef (which litera lly m eans to define w h a t’s entered) to add
a d d itio n a l nam es for d a ta types, b u t th is is not p e rm itted in C#. As s ta te d from th e
beginning, C# is a stro n g typed language; it cannot use access m odifiers to create
unsigned or extended d a ta types, and it does not allow for th e am biguity perm itted by
user-defined d a ta types. Thus, if a C/C++ com m and is encountered, rem em ber th a t it
can be quickly replaced w ith the appropriate explicit definition (see Exam ples 1.46 and
1.47).

49
C# and Game Programming

E xam ple 1.46. C++.

#include <iostream>
using namespace std;

void main (void) {


typedef int cat; // cat becomes a metonym for int
cat number = 1;
}

E xam p le 1.47. C#.

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.

Using, System, and Namespace


One very noticeable change from C++ to C# is the altered use of the i o s tr e a m classes,
and hence, the keywords using and namespace. These redefined commands are a result
of the larger object-oriented changes found in the Base Class Libraries. The most notable
alterations include the reference to the nam espace System (as in using System), and
the external user-defined namespaces (as in Chapterl, etc.). System is one of the larger
nam espaces developed for the Base Class Library, with our own Chapter 1 representing a
m uch sm aller grouping. We can also nest and/or expand1those nam espaces to include a
hierarchical structure. While we’ve already worked with m any of the abbreviated ex­
amples, it is also im portant to become fam iliar w ith the extended form (as in Exam ple
1.48).

When we place our coding inside a namespace, we are actually declaring a


scope or globally unique partition. The types contained in that namespace
are then accessible through both direct access (from within that body) and
through the using name space -directive, which allows us to use its values
without qualification.

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).

1 T h a t is, to include w ith in a seco nd ary o r m ultiple s e t of files.

51
C# and Game Programming

E xam ple 1.49. U sin g and nam espace.

using sys = System;

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

Data Types: Prefixes

Boolean b

BYTE (unsigned char) by

Character (for types char, WCHAR, and TCHAR) c

Integer used as x, y lengths (c stands for count). cx, cy

D ouble WORD (unsigned long integer) dw

Function Fn

Handle H

Integers i

Integer used as x, y coordinates *,y

f stands for "flags" f

Long Integers I

String s

String term inated by 0 character Sz

Pointer p

Short Integers n

WORD (unsigned short integer) w

T able 1.6. Prefixes for various data types.

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.

Common Errors, Problems, and Pitfalls

1. Like C and C++, C# is a case-sensitive language; thus,


any discrepancy in case settings will resu lt in an error. For
example, incorrectly writing void as either VOID or Void would
resu lt in a syntax error. (Hint: Most compilers identify keywords
w ith a change in color).
2. The m ain m ethod should have th e word M ain followed by both
opening and closing parentheses.
3. The program should begin w ith an opening brace, e.g., {and end
w ith a closing brace}.
4. Com m ents require two forw ard slashes, as in //, not back slashes
\ \ . In addition, com m ents spanning two or more lines require

54
Chapter 1: C# from the Beginning

both an opening forw ard slash and an asterisk, and a closing


aste risk and forw ard slash, as in /* com m ents here */.
5. If you can’t find the error, try rem oving all the com m ents and any
other unnecessary coding,saving the file under a different nam e so
th a t you can revert back to the original after you’ve isolated the
error

6. Braces placed after a comm ent (as in // th is is a note}) are


included as p a rt of the comm ent and will not be read by the
compiler.
7. The newline character m ust be w ritten as forw ard slash n (/n);
using the back slash will resu lt in a syntax error.
8. Both the W rite and W riteLine com m ands require encapsulating
parentheses.
9. If you’re using an older C++ compiler, you’ll need to use #include
<iostream > and the nam espace std or <iostream .h> header
w ithout using the nam espace commands.
10. Did you follow the rules given in th is chapter on nam ing
variables? B reaking these rules usually causes syntax errors.
11. One error can cause your compiler to spit out several compiling
errors; th u s you should alw ays atte m p t to recompile your
program if no other errors seem likely.
12. Did you m isspell the variable’s nam e? U ndefined statem en t
errors are usually caused by such m isspellings.
13. Did you forget the comma when adding several variables to a
single line?
14. Did you forget a semicolon or did you p u t one were it w asn’t
suppose to be?
15. Did you forget th e single quote or use double quotes when
assigning a character variable?
16. You m ust use an integer value w hen calculating a rem ainder.
17. Listing any keywords or variables w ith a space betw een the
lette rs is alw ays an error.

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.

1. Define the term s .Net and C#. Q uestions


2. Who was the chief architect of C#?
3. Who is the a u th o r of th is book?
4. W hat is ECMA certification?
5. Define m anaged code.
6. W rite an algorithm th a t explains how to play the card game fifty-
two pickup.
7. W rite and compile a “do-nothing” program .
8. Define the types of com m ents used in C#.
9. W rite a “do-nothing” program th a t includes an in itial comment
describing the program s purpose and th en two other com m ents
m arking the beginning and the ending of the m ain method.
10. W rite a program th a t displays the words “Hey, look at me! I’ve
w ritten a program !”
11. C ontinuing from Q uestion 10, use th e newline character to
sep arate “Hey, look a t me!” from “I’ve w ritten a program !”
12. C ontinuing from Q uestion 10, use the W rite L in e command,
replace the newline character w ithout altering the program s
output.

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.

15. Continuing from Question 13, using only the declared


statem ents, assign appropriate values to each variable.
16. U sing only integers, w rite a program th a t adds and then
subtracts two num bers.
17. Using either single or double precision values, w rite a program
th a t first m ultiplies and th en divides two num bers.
18. W rite a program th a t finds the digits after the decimal point for
any irrational number.
19. W rite a program th a t reads in a character and echoes it back
using both W r i t e and W r i t e L i n e .
20. W rite a program th a t uses both increm enting and decrem enting
operators.

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

T iterations. It also covers an introduction to m ethods, basic polymorphism (over­


loading), and recursion. M athem atical abbreviations are also discussed in this chapter, as
well as Boolean expressions, short circuit evaluations, and type casting.

The i f Statem ent


Before we can begin to write even the simplest of games, we’ll have to first offer our players
some choices. These choices will enable players to choose correctly or incorrectly, which
consequently will allow them to either win or lose. Luckily, C# offers an abundance of ways
to accomplish this task; the sim plest of these is the i f statem ent, thus, this is where we’ll
begin.
All of our program s have followed a single path. T hat is, they do one step and th en
the next w ithout regard for our input. Exam ple 2.1 dem onstrates this nonresponsive,
linear form of program m ing. To test this program , try in p utting som ething other th en
the requested data.

59
C# and Game Programming

E xam ple 2.1. A n o n r e sp o n siv e program .

using System;

namespace Chapter2 {
class Classl {
static void M a i n () {
// Begin main
int cResponse;

// Step 1 - try typing N for NO


C o n s o l e .WriteLine ("Input <Y> for YES: ")

// 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.

E xam p le 2.2. U sin g th e i f sta tem en t.

using System;
namespace Chapter2 {
class Classl {

60
Chapter 2: Branches, Loops, and Functions

static void Main() {


int cResponse;

// Step 1
Console .Write (" Input <Y> for YES: 11) ;

// Step 2
cResponse = C o n s o l e .R e a d ();

// Step 3 - if response equals 'Y'


if ((char) cResponse == 'Y')
Console .WriteLine (f,\n You typed Y\n");
}
}
}

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).

E xam p le 2.3. U sin g th e i f sta te m e n t w ith n u m erica l data.

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 ());

// Step 3 - numbers do not require quotes


if (iAnswer == 2)
Conso le .W ri te Li ne ("\n That is c o r r e c t !\n");

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.

Two equal signs “= =” meaning “equal to,” e.g.,


1. - if (variable 1 = = variable2)
- // 5 is equal to 5
Less than symbol “<” meaning “less than,” e.g.,
2. - if (variable 1 < variable2)
- // 5 is less than 10
Less than or equal to “<=” meaning “less than or equal to,” e.g.,
3. - if (variable 1 <= variable2)
- // 5 is less than or equal to 10
Greater than “>” meaning “greater than,” e.g.,
4. - if (variable 1 > variable2)
- // 20 is greater than 10
Greater than or equal to “>=” meaning “greater than or equal to,” e.g.,
5. - if (variablel >= variable2)
- // 20 is greater than or equal to 10
Not equal “!=” meaning “Not equal,” e.g.,
6. - if (variablel != variable2)
- // 20 does not equal 10

T able 2.1. C om p arison O p erators.

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.

The e ls e Statem ent


E ls e is the first logical extension to the i f statem ent. It adds an additional line of reason­
ing and an additional p ath for program s to follow. E ls e cannot be used by itself; it links
easily to the ta il end of the i f structure. Exam ple 2.4 uses the i f - E l s e statem en t to
redefine the previous program . The addition of e 1 se negates the need for the second i f
statem ent, and its simplicity adds a more elegant feel to our coding.

E xam p le 2.4. The i f - e l s e sta te m e n t.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
double Answer;

C o n s o l e .W r i t e ("1 + 1.5 = " ) ;


input = C o n s o l e .R e a d L i n e ();
Answer = d o u b l e .Parse(input);

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

The i f - e l s e sta te m e n t works in basically the sam e m an n er as th e i f statem en t.


The term e l s e im plies “in all other cases,” or an “everything else h e re ” type situation.
This ability to a lte r the direction of our program s is w hat defines it as a program m ing
technique, i f - e l s e , however, is still lim ited to two directions, of which the second is
nonspecific. To specify the second direction or m ultiple paths, we would have to use the
th ird type of i f sta te m e n t known as the e l s e - i f statem en t.

The e l s e - i f Statem ent


E l s e - i f , like e l s e is a d e p e n d en t or secondary ex ten sio n to th e o rig in al i f s ta te ­
m ent. Yet e l s e - i f definitely adds som ething new to th e table. Since e l s e - i f m u st
be ad d ed a fte r a n i f s ta te m e n t, w e’ll a lte r th e previous program once again, th is
tim e giving th e u se r a little m ore to go by th a n ju s t th e w ord w rong—see E xam ple
2.5.

E xam p le 2.5. The else-if sta te m e n t.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
double Answer;

Console .Write (111 + 1.5 = ");


input = C o n s o l e .R e a d L i n e ();
Answer = d o u b l e .P a r s e (input);

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

E l s e - i f includes a second conditional response with respect to i f . Because e l s e - i f state­


ments are dependent, they are only read by the computer if the first i f statement is false (see
Example 2.6).

E xam p le 2.6. The e ls e -if sta te m e n t as a d e p e n d e n t sta tem en t.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
double Answer;

C o n s o l e .Write ("1 + 1.5 = 11) ;


input = C o n s o l e .ReadLine ();
A nswer = double .Pa rse (input);

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!!!");

C o n s o l e .WriteLine ("I hate the if statement!");


}
}
}

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

Compound i f Statem ents


A compound statement is a group of statem ents combined into a bundle enclosed by a pair
of braces. A compound i f statem en t is an i f statem en t th a t executes this bundle as if it
were a single action. The proper way to w rite a compound statem ent is dem onstrated in
Exam ple 2.7. (Note: E ither e l s e or e l s e - i f could still be used simply by placing those
keywords a t the end of the compound statem ent.)

E xam p le 2.7. A com p ou n d i f sta te m e n t.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
float MyNumber;

C o n s o l e .W r i t e L i n e ("How old are you? " ) ;


input = C o n s o l e .R e a d L i n e ();
MyNumber = f l o a t .P a r s e (input);

if (MyNumber >= 18) { // compound statement


C o n s o l e .W r i t e L i n e ("\n You're an adult");
C o n s o l e .W r i t e L i n e ("You can vote\ n" );
} else
C o n s o l e .W r i t e L i n e ("\n Your turn will come ") ;
}
}
}

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

E xam p le 2.8. C om pound if and else-if sta te m e n ts.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
float MyNumber;

C o n s o le .W ri te ("How old are you? ") ;


input = C o n s o l e .R e a d L i n e ();
MyNumber = f l o a t .P a r s e (input);

if (MyNumber >= 18)


Consol e. Wr it eL in e("You 1re an adult\n" + "You can vot e\ n" );
else if (MyNumber == 17)
C o n s o l e .W r i t e L i n e ("Your turn will come \n");
else if (MyNumber == 16) { // compound statement
C o n s o l e .W r i t e ("\n Don't rush it boy you'll only be young
once\n"
+ "How old are you again? ");
input = C o n s o l e .R e a d L i n e ();
MyNumber = f l o a t .P a r s e (input);
} else
C o n s o l e .W r i t e L i n e ("\n You're just too y o u n g !!!\ n" );
}
}
}

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

and, or, and not

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

2. or ( | | ) meaning “only one needs to be true for the statement to be true”


- if ( v a r i a b l e l == v a r ia b le 2 | | v a r ia b le 2 < v a r ia b le 3 )
/ / 20 = 20 or 20 < 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

T able 2.2. The and, o r , an d n o t o p era to rs

E xam ple 2.9. R e d u cin g i f s ta te m e n ts by u sin g th e or op erator.

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

C o n s o l e .W r i t e ("How much do you weigh?");


input = C o n s o l e .R e a d L i n e ();
Weight = double.Parse (input);

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 ();
}

if (Weight < 35) {


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 ();
}

if (Age < 3 || Weight < 35) {


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)].

Nested i f Statem ents


J u s t as it is possible to w rite a program using more th a n one i f statem ent, it is also
possible to place one or more i f statem en ts inside a compound i f statem ent. These
in te rn al or nested i f statem en ts have nothing to do w ith the controlling i f statem ent,
but since we’re using the sam e keyword, it can become confusing. N ested i f statem en ts
work ju st as independently as any other if statem en t placed anyw here in the program ,
including inside a compound e l s e or e l s e - i f statem ent. Exam ple 2.10 dem onstrates a
complex blend of nested i f and e l s e - i f statem ents.

69
C# and Game Programming

E xam p le 2.10. N e sted i f and e l s e - i f sta te m e n ts.


using System;

namespace Chapter2 {
class Classl {
static void Main() {
string Input;
float Age, Weight;
int iQuickAnswer;

// Note: you'll want to hit return before entering the second


// answer
C o n s o l e .W r i t e ("How old are you and how much do you weigh? ");
Input = C o n s o l e .ReadLine ();
Age = f l o a t .P a r s e (Input);
Input = C o n s o l e .R e a d L i n e ();
Weight = f l o a t .P a r s e (Input);

if (Age < 3 || Weight < 35) { // start compound if statement


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? ");
iQuickAnswer = C o n s o l e .R e a d ();

if (iQuickAnswer == 'y') // nested if statement


C o n s o l e .W r i t e ("\n Good, but using it would be
b e t t e r .\ n" );
else { // nested else compounded
C o n s o l e .W r i t e ("\n No, do you care about your
b aby ? \ n " );
if (iQuickAnswer == 'y') // nested if in nested else
C o n s o l e .W r i t e ("\n Well then get a car seat!\n");
else if (iQuickAnswer == 'n') // nested else-if in
// n e s t e d else
C o n s o l e .W r i t e ("\n You s i ck e n me! \ n"
+ "\n Your baby is worth it!\nfl);
else // nested else in nested else
C o n s o l e .W r i t e ("\n Your baby is worth it!\n");
}
} // end compound if statement
else if (Age > 8 5 || Weight > 500)
C o n s o l e .W r i t e L i n e ("\n Sorry I asked!\n");

70
Chapter 2: Branches, Loops, and Functions

M athem atical Abbreviations


Sometimes, as program s become larger and more complex, they also become wordy and
draw n out. To alleviate this problem, program m ers often use abbreviations. Our coverage
here mimics w hat we’ve already studied under the section on arithm etic. Table 2.3 defines
these shortcuts, and Example 2.11 dem onstrates how they’re w ritten. I’ve included arith ­
metic statem ents in both longhand and shorthand forms to make them easier to compare.
I’ve also thrown in several i f -statements, which were already covered in this chapter. You’ll
need to rerun this program a minimum of five times, entering the proper characters once for
each shortcut. You might also w ant to try removing the longhand statem ents or rewriting it
using the w h ile loop (explained in the next section).

E xam p le 2.11. S h o rth a n d n o ta tio n .


using System;

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;

C o n s o l e .W r i t e L i n e ("\n Enter one symbol: \n addition (+) "


+ "\n subtraction (-) \n multiplication (*)"
+ "\n division (/), or \n remainder (%): ");
iCharacter = C o n s o l e .R e a d ();

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);
}

if (iCharacter = = ' - ' ) {


iVariablel = iVariablel - iVariable2;
Conso le .W ri te Li ne ("\n Your longhand difference is "
+ iVariablel);
iVariable3 -= iVariable2;
Conso le .W ri te Li ne ("\n Your shorthand difference is "
+ iVariable3);
}

if (iCharacter == '* ') {


iVariablel = iVariablel * iVariable2;
Console .WriteLine ("\n Your longhand product is 11
+ iVariablel);
iVariable3 *= iVariable2;
C o n s o l e .W r i t e L i n e ("\n Your shorthand product is "
+ iVariable3);
}

if (iCharacter = = ' / ' ) {


iVariablel = iVariablel / iVariable2;
C o n s o l e .WriteLine ("\n Your longhand quotient is "
+ iVariablel);
iVariable3 /= iVariable2;
Console.WriteLine ("\n Your shorthand quotient is "
+ iVariable3);
}

if (iCharacter = = ' % ' ) {


iVariablel = iVariablel % iVariable2;
C o n s o l e .W r i t e L i n e ("\n Your longhand remainder is "
+ iVariablel);
iVariable3 %= iVariable2;
Console .W ri te Li ne ("\n Your shorthand remainder is "
+ iVariable3);

72
Chapter 2: Branches, Loops, and Functions

Arithmetic (int iNumber = 5;) Abbreviates to Returns


Addition: iNumber = iNumber + 1; iNumber += 1; 6
Subtraction: iNumber = iNumber - 1; iNumber -= 1; 4
Multiplication: iNumber = iNumber * 2; iNumber *=2; 10
Division: iNumber = iNumber / 2; iNumber /= 2; 2
Remainders: iNumber = iNumber % 2; iNumber %= 2; 1

// A ssu m e V a r ia b le l = S an d V a r ia b le 2 = 2 and th a t t h e y 'r e a


n u m e r ic d a ta t y p e . _________________________________________________________________________________ _ _ _
1 . A d d it io n :
V a r ia b le l = V a r ia b le l + V a r ia b le 2
V a r i a b l e l += V a r i a b l e 2
/ / v a r i a b l e l now e q u a ls 7 s in c e - 7 = 5 + 2
2 . S u b t r a c t io n :
V a r ia b le l = V a r ia b le l - V a r ia b le 2
V a r i a b l e l ~= V a r i a b l e 2
/ / v a r i a b l e l now e q u a ls 3 s in c e -______ 3 = 5 - 2 _____________________________________
3. M u lt ip lic a t io n :
V a r ia b le l = V a r ia b le l * V a r ia b le 2
V a r ia b le l *= V a r ia b le 2
// V a r ia b le l now e q u a ls 10 s in c e - 10 = 5 * 2 _ _ ..................
4 . D iv is io n
V a r ia b le l = V a r ia b le l / V a r ia b le 2
V a r ia b le l / = V a r ia b le 2
/ / V a r ia b le l now e q u a ls 2 .5 s in c e - 2 .5 = 5 / 2 (W h e n
V a r ia b le l is e i t h e r f l o a t o r d o u b le )
/ / V a r ia b le l now e q u a ls 2 s in c e - 2 = 5 / 2 (W h e n v a r ia b le l
is of ty p e i n t e g e r ) ________________________________________________________________________________________
5 . R e m a in d e r s :
V a r ia b le l = V a r ia b le l % V a r ia b le 2
V a r i a b l e l %= V a r i a b l e 2
/ / V a r i a b l e l now e q u a ls 1 s in c e - 1 = 5 % 2 (V a r ia b le l s h o u ld
o n ly be u s e d w it h in t e g e r s )
/ / Rem em ber % s ta n d s f o r th e r e m a in d e r of 1 as in 5 / 2__________________

T able 2.3. N u m eric A b b rev ia tio n s

The w h ile Loop


In the last section, we were forced to restart our program five times in order to test the results of five
characters. Although this might be acceptable in a book which teaches programming, it would not

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.

E xam ple 2.12. A w h ile loop lim ite d to fiv e p a sse s.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
int iCounter_l = 0;

while (iCounter_l < 5) { // while loop


Console.WriteLine(iCounter_l++);
}

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.

E xam p le 2.13. T h is w h ile loop en d s w h en I say it en d s, got it?

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string Quit = "no";

while (Quit != "yes") {


C o n s o l e .W r i t e ("\n Would you like to end this loop? ");
Quit = C o n s o l e .R e a d L i n e ();
}

Console.WriteLine ("Program c o m p l e t e !\n ");

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.

E xam p le 2.14. H ey, you brok e m y w h ile loop!

using System;

namespace Chapter2 {
class Classl {
static void M a i n () {
string Quit = "no";

while (Quit != "yes") {


break; // breaks loop
Console.Write ("\n Would you like to end this loop? ");
Quit = C o n s o l e .ReadLine ();
}

Console.WriteLine ("Program c o m p l e t e !\n ");

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).

E xam p le 2.15. The k ey w o rd c o n tin u e .

using System;

namespace Chapter2 {
class Classl {
static void Main() {
int iVariablel = 10, iVariable2 = 0;

while (iVariablel == 10) { // while loop


iVariable2 = iVariable2 + 1;
if (iVariable2/iVariablel < 1)
continue;
iVariablel = iVariablel - 1;
}

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!

E xam p le 2.16. B a ttle Bit: The T ext A d ven tu re.

/* Y o u ’re a lieutenant in earth's toughest military fleet. Your


* current mission is to guard earth's intergalactic conference hall. */
using System;

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

/* Game introduction - explains to the player what he needs to


* do, why he is doing it. The introduction should also, be
* used to set the games mood and excite the player. */

C o n s o l e .W r i t e L i n e ("\n Captain, aliens are attempting "


+ "to land p e a c e f u l l y !\n"
+ "What? How dare they and on the day we're suppose "
+ "to start peace talks.\n"
+ "It just goes to show you, you just can't trust "
+ "those alien scum.\n"
+ "Lieutenant, lock target, I don't want to see one "
+ "alien left alive.\n"
+ "But captain, isn't that the ambassadors ship!\n"
+ "And wasn't he suppose to be coming today?\n"
+ "Lieutenant, are you going to target the alien "
+ "ship or not?\n"
+ "But sir. \n Type in the ships location and fire
soldier!\n"
+ "But s i r !\n"
+ "Lieutenant, you'll take out that alien scum or I'll "
+ "take you o u t !\n"

78
Chapter 2: Branches, Loops, and Functions

+ "(The captains gun points oddly at your head.) "


+ "Got it? Yes sir!\n");

// location of ship - this just makes it harder to find the


// ship
iAlienShip = ((iAlienShip * iAmmo) / (iTarget + 1)) + 3;

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
}

// The location of the ship moves with each shot


if (iTarget == 0) {
iTarget = 1;
}
iAlienShip = (iAlienShip * iAmmo) / iTarget;
}

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");

Console.WriteLine ("\n Game Ove r\ n" );

79
C# and Game Programming

+ "(The captains gun points oddly at your head.) M


+ "Got it? Yes sir!\n");

// location of ship - this just makes it harder to find the


// ship
iAlienShip = ((iAlienShip * iAmmo) / (iTarget + 1)) + 3;

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
}

// The location of the ship moves with each shot


iAlienShip = (iAlienShip * iAmmo) / iTarget;
}

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");

Console.WriteLine ("\n Game Over\n");


}

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 .

E xam p le 2.17. A d o - w h ile loop I.

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.

E xam p le 2.18. A d o - w h ile loop II.

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

Quit = C o n s o l e .R e a d L i n e ()/ // users input


} while (Quit != "yes");

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.

E xam p le 2.19. N e sted w h ile an d d o - w h ile loop s.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
// Begin main
int iNumber = 0 ;
string Quit;

do { // begin do-while loop


C o n s o l e .W r i t e ("\n Would you like to end this loop? ");
Quit = C o n s o l e .R e a d L i n e (); // users input

while (Quit == "yes" && iNumber < 10) { // nested while


//loop
Console .W ri te Li ne ("We're sorry the exit you have
chosen "
+ "is not available "
+ "at this time\n please try again");
Quit = C o n s o l e .R e a d L i n e ();
iNumber++;
}

} while (Quit != "yes"); // end do-while

82
Chapter 2: Branches, Loops, and Functions

Console.WriteLine("Program complete!\n");
}
}
}

If you’re trapped, the secret to escaping is in understanding the comparisons.


Program
W alkthrough
First, if you enter anything other then “yes” you can’t exit the do/while-loop.
If you do enter “yes,” the program goes into the nested whi le loop. After entering
the while loop, if you enter anything other than “yes,” you’re forced to repeat
the do-while loop and the process starts all over. However, if you enter “yes”
the nested while-\oop keeps repeating itself.
The solution requires you to enter “yes” eleven times. Once to get into the while
loop and ten times to get out. The incrementing variable iNumber will cause
the nested while loop, to become false, and since the character’s string “Quit”
is still equal to “yes,” the do-while loop will also false and the loop will end.

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

E xam p le 2.20. The f o r loop.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
int iCounter 1;

for (iCounter_l = 0; iCounter_l < 5; iCounter_l++) {


C o n s o l e .W r i t e L i n e (iCounter_l);
}

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.

N esting is ju st as legal and useful in f o r loops as it is in the other loops introduced


earlier, but it is also ju st as dangerous (or as trying) when you are caught in an infinite
loop. Thus, you should avoid using th e f o r loop’s tracking variable for anything other
th a n keeping track of th a t f o r loop. If you th in k you’re up to it, you can go back and
rew rite the w h ile and d o - w h ile program s using only f o r loops.

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.

The s w it c h Statem ent


The s w itc h statem ent, like the i f and e l s e - i f statem ents, is used to execute a s ta te ­
m ent, or set of statem ents, depending on a value. However, unlike the i f and e l s e - i f
statem ents, the s w itc h statem en t doesn’t use comparison operators; instead, it simply
reads the value of the variable and attem p ts to direct the program to the proper chan­
nel. A second keyword, c a s e , is also used in th is process. The keyword c a s e is w ritten
and used m ultiple tim es from w ithin th e s w itc h statem ent,; each s w itc h statem ent
holds a num eric or character value for comparison. If the value held by a c a s e s ta te ­
m ent m atches the value read by the s w itc h statem ent, th en everything following th a t
c a s e statem en t is executed.
A nother useful keyword used w ith the s w i t c h statem en t is d e f a u l t , m eaning
w hen no other case m atches, d e f a u l t is usually placed a t the end of a switch s ta te ­
m ent, th u s allowing us to execute selected statem en ts based on the fact th a t they do not
m atch any of the previous values (see Exam ple 2.21).

E xam p le 2.21. s w it c h sta te m e n t.

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 ();

switch (Grades) { // switch statement


case 'A':
case 1a 1:
Console.WriteLine ("You'll make a great programmer");
break;

case 1B 1:
case 'b 1:
Console.WriteLine ("You're sure of yourself");
break;

case 'C ':


case 'c ':
Console.WriteLine ("You don't let hard work keep you
d o w n " );
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

E xam p le 2.22. S w itc h sta te m e n t c o n tin u ed .

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
int byNumber;

C o n s o l e .W r i t e ("Enter a number greater than one: ");


input = C o n s o l e .R e a d L i n e ();
byNumber = i n t .P a r s e (input);

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;
}

C o n s o l e .W r i t e L i n e ("\n Program complete\n");


}
}
}

It is possible to have switch statem en ts using either character or integer data


types, but the set case types m ust be literal or variable constants. You cannot set two cases
to the sam e value even if it’s w ritten as a variable, and you cannot have more th a n one
default in any single switch statem ent, switch statem ents can have if statem ents in their
cases, and if statem ents can have switch in th eir compound statem ents. In addition, you
can place switch statem ents in while and do-while loops or w rite those loops into case

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

Specifier Definition Example


1. %d Holds positive or negative whole numbers scanf(“%d’\ &variable 1);
-int variable! (signed int variablel) printf(“Your number is %d”, variablel);
2. %u Holds only positive whole numbers scanf(“%u”, &variablel);
-unsigned int variablel printf(“Your number is %u”, variabel);
3. %f Holds floating point (real) numbers scanf(“% f\ & variablel);
-float variablel printf(“Your number is % f\ variablel);
4. %c Holds a single character data type scanf(“%c”, &variablel);
-char variablel printf(“Your symbol is %c”, variablel);
5. %s Holds a string or array o f characters scanf(“%s”, &variablel);
-char variablel [7] (or any positive number) printf(“Your word is %s*\ variablel);

T able 2.4. U sin g C o n v ersio n sp e c ifie r s w ith p r in tf () and s c a n f ().

Two interesting command functions th a t continue to evolve through the C languages


are the old style and m em ber functions p u t s and g e t s . The original p u t s was accessed
in essentially the sam e m anner as p r i n t f , but w ith the restriction th a t it could only
display character data (as in p u t s ( “th is is a te st 1, 2, 3.”);. G e ts, like s c a n f , was also
used to read data, b u t everything read is interpreted as a character string. This can also
be thought of as an array (which w ell discuss in C hapter 4). The extended m em ber func­
tion versions of these two types are unfortunately lim ited to only single character refer­
ences as in c o u t .p u t s ( 'A ' ) and c i n . g e t ( c h a r a c t e r ) , so th eir practicality is
lim ited. Two alternative replacem ents for these older style functions are c i n . g e t l i n e
( c h a r a c t e r s , s i z e o f l i n e ) and c o u t . w r i t e ( c h a r a c t e r s , s i z e o f l i n e ) These
will also be explained in C hapter 4 (see Example 2.23). Note th a t while the p u ts function
autom atically moves data to the next line, c o u t . w r i t e does not.

E x a m p le 2.23. C/C++ v e r su s C#.

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

C o n s o l e .Write ("\n Hello, please enter a number: ") ;


// printf ("\n Hello, please enter a number: ");
// cout << M\n Hello, please enter a number: ";
// s t d ::c o u t .w r i t e ("Please enter a name: ", 24);
// puts("Please enter your name:");

Number = i n t .Parse(Answer = C o n s o l e .ReadLine ());


// scant("%d", &Number);
// cin >> Number;
// s t d ::c i n .getline(name, sizeof(name));
// gets(Number);

C o n s o l e .WriteLine ("You entered {0} is that correct?", Number);


// printf ("\n You entered %d is that correct?", Number);
// cout << "\n You entered " << Number << " is that correct?";

Answer = C o n s o l e .ReadLine ();


// scant ("%s", &Answer);
// cin >> Answer;

We could also convert m ultiple references, including form atting strings, to represent
the change in notation (see Example 2.24).

E xam p le 2.24. C o n v ertin g m u ltip le r e fe r en ce s.


Console.WriteLine("\n You entered the nurber {0, D} and also the letter {1}", iNurber, cAnswer) ;
printf ("\n You entered the nurber %d and also the letter %c\n", iNurrber, cAnswer);

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

could also in clu d e a n u m eric s u b s titu te , n am ely th e n u m eric c o n s ta n ts one a n d


zero w ith zero e q u alin g false and th e value one or any nonzero positive or neg ativ e
n u m b e r e q u a lin g tru e . In C#, how ever, th is n u m eric s u b s titu tio n is no t allow ed.
Exam ple 2.25 d e m o n stra tes th is sequence for a while loop, b u t you should a tte m p t
to re w rite th e p ro g ram as a do-while loop before proceeding to th e n ex t section.

E xam p le 2.25. B o o le a n e x p r e ss io n s —tru e or false.

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

if (Test == "yes" || Test == "YES")


Variablel = false;
} // end while loop

Console.WriteLine ("Program complete!");


}
}
}

Short Circuit Evaluation


Short circuit or partial comparisons are comparisons th a t can be deduced w ithout testing
th e entire statem ent. This deduction can be m ade for logical types && or | | , but w ith
opposite results, as shown in Table 2.5.

91
C# and Game Programming

Non-specific Equations Evaluation Process Reasoning


1. (True && True) Complete evaluation True + True = True
2. (True && False) Complete evaluation True + False = False
3. (False && True) Short circuit evaluation False + Test Skipped = False
4. (False && False) Short circuit evaluation False + Test Skipped = False
5. (True II True) Short circuit evaluation True + Test Skipped = True
6. (True II False) Short circuit evaluation True + Test Skipped = True
7. (False II True) Complete evaluation False + True = True
8. (False II False) Complete evaluation False + False = False

T able 2.5. True and fa lse d eterm in a tio n s.

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.

E xam ple 2.26. A p a rtia l co m p a riso n u sed to sa feg u a rd ru n tim e errors.


Co n s o l e .W r i t e L i n e ("Enter any number other than zero: ") ;
variablel = C o n s ol e.R e a d () ;

// Some smart user enters zero, the system crashes,


while (5/variablel < 1) ;
// Later that day... you're fired!

// Alternatively, you could have used short


// circuit evaluation. And later that same day,
while (variablel != 0 && 5/variablel);
// you could have been surfing the web as RedHotPartyPants.

The Conditional Operator


The conditional operator, which is also described as a ternary operator (because of its three
operands), is essentially an abbreviated i f - e l s e expression th a t uses two symbols: a

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.

First, the comparison is made:


x = y ? 41 : 72

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.

Comparison ? Equationl : Equation2:

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).

E xam p le 2.27. U sin g T oU pper.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
int Response;

C o n s o l e .W r i t e ("Input <Y> for YES: ");


Response = C o n s o l e .R e a d ();
Response = c h a r .T o U p p e r ((char) 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):

sin 0 = y/r esc 0 = r/y


cos 0 = x/r sec 0 = r/x
r = hypotenuse ta n 0 = y/x cot 0 = x/y

esc 0 = 1/sin > sec 0 = 1/cos, co t, = 1 /ta n ,


tan = sin 0 /cos 0 cot 0 = cos 0/sin 0 sin20 + cos2Q
0 = s/r (where s is the signed arc length)

E xam ple 2.28. A few com m on m ath fu n ctio n s.

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

Co n s o l e .W r i t e ("Enter a number and I ’ll give you its square


r o o t : ") ;
input = C o n s o l e .ReadLine ();
numberl = d o u b l e .P a r s e (input);

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);

Console.WriteLine("Math.Ceiling(3.2) = {0}", numberl);


C o n s o l e .W r i t e L i n e ("M a t h .F l o o r (3.9) = {0}", number2);

Additional extensions include some useful functions th a t determ ine abso­


lute values and references th a t convert from character data to integer and double, but the
most im portant extension relating to game program m ing is the random num ber genera­
tor. Pseudo-randomly generated num bers, based on the in tern al clock, are especially im ­
portant to us in game program ming because they help guide w hat the user sees as sponta­
neous events and an unpredictable opponent. This is also the groundwork for simple a rti­
ficial intelligence, but I won’t get into th a t u ntil the next chapter. For now, let’s ju st see
how far we can push these functions and everything else we’ve studied in the last two
chapters with a sequel to our Battle Bit game Battle Bit II—This is War! (See Example 2.29).

E xam p le 2.29. B a ttle B it II: T h is is War!


/* Battle Bit II - THIS IS WAR! Some mad dog soldier shot down the
* alien Ambassador's convoy and it sparked an intergalactic war.
* Earth's defenses was weak form warring with several hundred other
* worlds. So now, it's all up to you. */
using System;

namespace Chapter2 {
class Classl {
static void Main() {

96
Chapter 2: Branches, Loops, and Functions

string input;
char cYesNo;

Random rnd = new R a n d o m ();

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;

C o n s o l e .W r i t e L i n e ("Captain, are you in there? Captain?\n"


+ "(Crying is herd form his quarters)\n"
+ "This is ground control to lieutenant Bob.\n"
+ "Your brother Major Tom has been shot down,\n"
+ "Repeat he has been shot down.\n"
+ "The aliens have destroyed our space outpost and \n"
+ "are now on route to Earth.\n"
+ "I know it's a long shot L ieutenant,\n"
+ "but I promised my wife and kids you'd stop them.\n"
+ "I'll do my b e s t . ..\n") ;

while ((iAlienShipl > 0 ) || (iAlienShip2 > 0)) {


C o n s o l e .W r i t e ("\n\n Enter targeting information: ");
input = C o n s o l e .R e a d L i n e ();
iTarget = b y t e .P a r s e (in put);

Console.WriteLine("{0},{1}", iAlienShipl, iAlienShip2);

if (Math.C e i l i n g (iTarget) == M a t h .C e i l i n g (iAlienShipl)


|| Math.Ceiling(iTarget) == Math.Floor(iAlienShipl)
|| Math.Floor(iTarget) == Math.Ceiling(iAlienShipl)
II Math.Floor(iTarget) == Math.Floor(iAlienShipl)) {
C o n s o l e .W r i t e L i n e ("Alien ship hit, you got him!");
iAlienShipl = -1;
}

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.Round (iTarget) > Math.Round (iAlienShipl))


&& (Math.Round (iTarget) > Math.Round (iAlienShip2)))
C o n s o l e .W r i t e L i n e ("\n You missed, try aiming a
little lower\n");
else if ((iTarget < iAlienShipl) && (iTarget <
iAlienShip2))
C o n s o l e .W r i t e L i n e ("\n You missed, try aiming
higher\n");
else
C o n s o l e .W r i t e L i n e ("\n I can't get a lock on
t he m\n");

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

if ((iAlienShipl + iAlienShip2) < 0)


C o n s o l e .W r i t e L i n e ("\n Good work lieutenant, "
+ "or should I say ca p t a i n .\n");
else
C o n s o l e .W r i t e L i n e ("\n BOOM!!! You're dead.\n");

C o n s o l e .W r i t e L i n e ("\n Game Over\n"


+ "\n Would you like to play again? (Y/N)");
input = C o n s o l e .R e a d L i n e ();
cYesNo = c h a r .Parse (i nput) ;
cYesNo = c h a r .ToUpper(cYesNo);
} while (cYesNo == 'Y');

98
Chapter 2: Branches, Loops, and Functions

Type Casting: Explicit Conversions


Before we jum p into user-defined functions, let’s cover one additional topic th a t actually
allows the conversion of num eric d ata into other various sized d ata types w ithout those
annoying w arnings about truncation and undue d a ta loss. Rem em ber th a t in C hapter 1
we covered im plicit conversions, which generally fell u nder th e category of sm aller to
larger transfers of data. Type casting is an explicit conversion and is used for conversion
from sm aller to larg er to protect ag ain st calculating errors, or lager to sm aller to red e­
fine those p a ra m ete rs w hen a v alue’s precision overshadow s its req u irem en t (see Text
Exam ples 1 and 2). In eith er case, the action of declaring an explicit conversion notifies
the compiler of our intention and autom atically reassigns those variables.

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).

E xam p le 2.30. Type ca stin g .


using System;
namespace Chapter2 {

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);

double number2 = (double)9 / (double)2; // returning 4.5


C o n s o l e .WriteLine(number2);

int integerl = (int) (4.7); // 4


Console.WriteLine(integerl);

if ( 9/2 >= (double)9 / 2 ) // always false


Console.WriteLine ("4 >= 4.5"); //Unreachable code detected

int integer2 = 9;
double number3 = (double)integer2 / 2; // 4.5
C o n s o l e .WriteLine(number3);

int integer3 = (int)((double)9 / (double)2 + .5); // 5.0


Console.WriteLine(integer3);

^ 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.

References, Values, and the Boxing Technique


In addition to being able to convert betw een the stan d ard types, we can also apply these
techniques to include both value to reference and reference to value conversions. This
process is m ost commonly referred to as boxing, w ith the term unboxing denoting the
re tu rn of those values to th eir original state. The process follows the sam e steps used
for basic type casting, b ut w ith an added note of caution w hen attem pting to re tu rn or
unbox our values: They can re tu rn to new variables, but those variables m ust be of the
sam e type as the original boxed data. The conversions are m ade using the keyword ob-
j ect, as shown in Exam ple 2.31.

100
Chapter 2: Branches, Loops, and Functions

Exam ple 2.31. B oxing and unboxing.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
double Happy = 4.0;

object MrBox = Happy;

// This line should work well


double StillHappy = (double)MrBox;

// This line may compile, but it will surely fail on execution


int NotHappy = (int)MrBox;
}
}
}

Introduction to User-Defined Functions


W hat are user-defined functions? Simply put, they are subprograms (subroutines or second­
ary methods) linked to a main or secondary method and subsequently used to carry out a list
of tasks when th a t method requests it. They can receive information from other functions
(including the m ain method) and they can send information back to their referencing func­
tion. They are both commands (like the predefined functions) and lines code used to imple­
m ent those commands, which we create as program m ers. Technically, everything placed
inside a user-defined function could just as well have been left inside its m ain method, but in
professional programs, this would lead to confusion and a very large and cluttered m ain
method. In addition, there are many techniques th at can be applied to user-defined functions
(including calls-by-references, overloading, and recursion), all of which can be applied re­
peatedly rath er th an asking the program m er to repeat th a t coding over and over again in a
single linear method. To start, w ell begin with the sim pler functions and then expand on
these topics one section a t a time.

10 1
C# and Game Programming

W riting Our First User-Defined Function


W riting a user-defined function isn’t th a t different from w riting a m ain function. In fact,
if you compared the two, you’d find th a t the underlying rules are basically the same. One
key advantage when declaring user-defined functions is their flexibility in descriptive nam ­
ing, which gives the program m er an in stan t, if not complete, description of w hat the
function will do. Microsoft’s H ungarian notation and Camel notation, along with the simple
rules of variable nam ing (all discussed in C hapter 1) are w hat we’ll use when declaring our
user-defined functions. O ur first example dem onstrates how a simple function is w ritten.
You should use th is exam ple to compare the two types of functions, e.g., M ain () versus
O urFunction () (see Exam ple 2.32).

E xam p le 2.32. Our fir st fu n c tio n call.


using System;

namespace Chapter2 {
class Classl {
static void OurFunction () {
/* This is a do nothing function */
}

static void Main () {


OurFunction ();
}

^ X Referencing a user-defined function is not unlike referencing a predefined


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.

E xam p le 2.33. Our se co n d fu n c tio n call.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
OurFunction ();
}

static void OurFunction () {


/* This is a do nothing function */
}
}
}

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

E xam p le 2.34. L ocal an d glo b a l v a r ia b le s.


using System;

namespace Chapter2 {
class Classl {
static int NumberOne, NumberTwo, GlobalTotal = 0;

static void Main() {


string input;

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);

Console.Write ("\n How many apples did Bobby shoplift? 11) ;


input = C o n s o l e .R e a d L i n e ();
NumberTwo = i n t .Parse (in put);

LocalTotal = NumberOne + NumberTwo;


OurFunction(LocalTotal);
}

static void O u r F u n c t i o n (int Total) {


GlobalTotal = NumberOne + NumberTwo;
C o n s o l e .WriteLine ("\n Good news, Johnny and Bobby were "
+ "arrested for shop li ft in g.\n"
+ "By the way would you like an apple? "
+ "I have {0} of them, {1} apples is a lot.", Total,
GlobalTotal);

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

Exam ple 2.35. V ariable scope.

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;

static void Main() {


// local variable (also the value of a gold bar in h e l l ) .
double GoldBar = 0;

Classl GlobalCA2 = new C l a s s l ();


C o n s o l e .W r i t e L i n e ("The value of gold on earth is "
+ "${0} per ounce", C l a s s l .Go ld Ba r);
C o n s o l e .W r i t e L i n e ("The value of gold in hell is "
+ "${0} per pound", GoldBar);
}
}
}

Functions th a t Return Values


O ur next step will be to re-equip our user-defined functions w ith nonvoid data types th a t
require some type of returning calculation. The keyword return passes back a single value
to the calling function. The value in question m ust be of the qualified type, and in cases
where the returning type is void it can be omitted. Return statem ents are required with all
nonvoid user-defined functions and methods. W ell begin by developing a simple, but effec­
tive function th a t finds the sum of two values and retu rn s th a t value to the m ain method
(we could also revise this example to compute th eir difference, product, quotient—see Ex­
ample 2.36).

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 ();

while (iNumberOne != 99) { // 99 ends loop


Co n s o l e .Write ("\n Guess the number, hint: 11
+ "it's between ten and three.\n"
+ "Can you guess it he, he, he? ");
input = C o n s o l e .R e a d L i n e ();
iNumberOne = i n t .P a r s e (i np ut );

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

Example 2.37. Letter generator.


using System;

namespace Chapter2 {
class Classl {
static void Main() {
char Letter = 1 Response;
string input;

C o n s o l e .WriteLine ("This program attempts to guess "


+ "the first letter\n"
+ "of your first name by randomly generated letters.\n"
+ "All you have to do is reply with a\"y\"\n"
+ "or a \"n\" after each guess\n"
+ "You can also enter \"q\" to quit "
+ "the game at any time.\n"
+ "My first guess is...\n");

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');
}

static char Le tt er Ge ne ra to r(int Letter) {


Random rnd = new R a n d o m ();
Letter = ((int)Math.Round(rnd.NextDouble() * 100));
while (!(Letter >= 65 && Letter <= 90)) {
Letter = ((int)Math.Ro un d(rnd.NextDouble() * 100));
}

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 .

E xam ple 2.38. M ain fu n c tio n w ith d ata ty p es.

using System;

namespace Chapter2 {
class Classl {
static int Main() {
return 0;

E xam ple 2.39. E m pty r etu rn sta te m e n ts.

using System;

namespace Chapter2 {
class Classl {
static void Main() {
return;

Passing Variables: Calls-By-Value


The call-by-value type mechanism is a mechanism used to transfer data between methods
th a t does not allow for continued access to the original fields. The data is then considered
to be a value type, which is appropriately stored on the “stack”—the com puter’s tem porary
memory—and will be removed, or “popped off,” w hen th a t m ethod is term inated. Again,
the changes in these secondary variables will not affect the original fields, nor will there be
deletions. The call-by-value form al param eters refer to the variables referenced from in ­
side user-defined functions as dem onstrated in Example 2.40 (a simple example th a t finds
the square root of a num ber).

108
Chapter 2: Branches, Loops, and Functions

E xam ple 2.40. P assin g our first variable.


using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
float number = 0, root = 0;

C on sol e. Wr it eL in e("This program will find the "


+ "square root of any number\n"
+ "To continue just enter a number when prompted\n"
+ "Your results will appear after you press enter\n"
+ "To quit just enter the number \"l\"\n"
+ "Enter your first value now: ”);
input = C o n s o l e .ReadLine ();
number = f l o a t .P a r s e (input);

while (number > 1 ) {


root = SquareRoot(number);
Console.WriteLine(root);

C o n s o l e .W r i t e L i n e ("Enter your next value now: ");


input = C o n s o l e .R e a d L i n e ();
number = f l o a t .Parse(input);
}
}

// This function generates square roots using N e w t o n ’s method

static float S q u a r e R o o t (float n) {


float testl, test2;
testl = n - (float).01 - ((n - (float).01) * (n - (float).01) - n)
/ (n * (n - (float) .01));
test2 = testl - ((testl * testl) - n) / ((n) * testl);

while (testl != test2) {


testl = test2;
test2 = testl - (testl * testl - n) / ((n) * testl);
}
return (test2);
}
}
}

10 9
C# and Game Programming

We could also have replaced that user-defined function with the predefined
function Math.Sqrt ().

W riting Functions as Black Boxes


The black box theory is simply a concept th a t stresses the idea th a t most, if not all,
functions should be thought of as independent or self-containing subprogram s. It also
reasons th a t the coding used to construct such a function does not need to be studied or
known by a program m er who only w ants to invoke th a t function. Thus, the only infor­
m ation needed to access a function is the proper passing variables and the knowledge of
w hat would be returned by the function. This is analogous to being able to drive a car, but
not knowing how to repair the engine. This is actually the norm in C#, since all predefined
functions are black boxes to most program m ers and the idea of enhancing them would
literally force us to open them up and redesign them to some new standard (which unfor­
tunately is usually necessary in game programming). Of course, if you were to write your
own user-defined functions, you’d certainly know how each one of them worked.
C reating a black box style function requires or restricts us to the use of encapsulated
controls. This, of course, m eans th a t you m ust avoid using global variables and th a t you
m ust include comments w ith every prototype to alert any other program m er to the v a ri­
able settings and to th eir results. In addition, you should keep in m ind th a t in later
chapters, we’ll be both reading and w riting to user-defined functions from separate files,
thus creating a real need for detailed comments explaining w hat these different function
calls do.

Applying the black box app ro ach to Exam ple 2.40


Let’s assume that you didn’t really understand the second portion of the last
example, but you used the square root function anyway. While it is a bit
disheartening to the mathematician in me, this will not affect the way the
program executes that data, and in fact, actually makes my point. If however,
that coding piqued your interest then here’s a quick overview of the mathematics
(see Example 2.41).

110
Chapter 2: Branches, Loops, and Functions

Exam ple 2.41. The square root function explained.

static float SquareRoot (float n) { // Newton's Method (Basic Calculus)


float testl, tes12; // Xn+1 = Xn - ' (Xn) n = 1, 2, 3,

testl = n-(float).01 - // X 0 = Guess-Estimate


((n-(float) .01)*(n-(float) .01) - n ) / (n*(n-(float) .01));
test2 = testl - ( (testl*testl)-n)/ ( (n)*testl)/

while (testl != t e s t 2 ) { / / X x = x 0 - (XQ2 - Number) / (Number*X0)


testl = test2; / / x 2 = x x - (X1 2 - N um ber)/ (Number*Xx)
test2 = testl - II X = X - (X 2 Nu mber)/ (Number*X )
(testl*testl - n) / / / X4 = X, (X, Number)/ (Number*X )
((n)*t est l); x. (X 2 - N um ber)/ (Number*X )
}
return (test2); // until X = X

Again, we can also reconstruct the last program using the predefined function
M ath.Sqrt () (see Example 2.42).

E xam p le 2.42. U ser-d efin ed v e r su s p r e d e fin e d fu n c tio n s.


using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
float number = 0, root = 0;

C o n s o l e .W r i t e L i n e ("This program will find the "


+ "square root of any number\n"
+ "To continue just enter a number when prompted\n"
+ "Your results will appear after you press enter\n"
+ "To quit just enter the number \"l\"\n"
+ "Enter your first value now: ");
input = C o n s o l e .R e a d L i n e ();
number = f l o a t .P a r s e (input);

m
C# and Game Programming

while (number > 1) {


root = (float)M a t h .Sqrt(number);
Console.WriteLine(root);

C o n s o l e .W r i t e L i n e ("Enter your next value now: ");


input = C o n s o l e .R e a d L i n e ();
number = f l o a t .Parse(input);

Well want to take the black box approach to most, if not all, of the predefined
functions listed in this text.

Passing Variables: Calls-By-Reference


The call-by-reference mechanism is an assignable m echanism , where the variables th a t
are passed to a function are not ju st passed as values, b ut include actual memory refer­
ences. Thus, by altering those values, we are also altering the values accessed by the m ain
program . These variables, then, are not created and destroyed as p a rt of a tem porary
stack; rather, they are created and stored by the heap, which is a memory location th a t
exists for the entire life of the program ’s execution. This has the minor disadvantage of not
allowing us to send numeric or literal constants as we could with the call-by-value m echa­
nism, but it does expand our options when dealing with otherwise globally restricted data.
The correct way to define a call-by-reference variable includes the use of the keyword r e f
preceding both the call and the function’s signature. The subprogram s can then be m ade
to carry out anything from a single, or subsequently large list of black box type actions (see
Exam ple 2.43 for a basic example of such referencing). Note th a t w ithout such referenc­
ing, all of the changes would have to be m ade from w ithin the m ain program .

E xam ple 2.43. A day at th e races.

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;

Co ns ol e. Wr it eL in e(" L e t 1s have a horse race.\n"


+ "To play select one of the horses below");

while (char.ToUp pe r( ch ar .Parse(input)) != 'N') {


Console .W ri te Li ne ("(1) for Whitefire\n"
+ "(2) for The Train and, \n"
+ "(3) for Noisy Glue\n");
Horse = C o n s o l e .ReadLine ();

TheRace(ref iNumberl);
TheRace(ref iNumber2);
TheRace(ref iNumber3);

T i e B r e a k e r (iNumberl, ref iNumber2);


TieBreaker(iNumber2, ref iNumber3);
TieBreaker(iNumberl, ref iNumber3);

C o n s o l e .W r i t e ("And the winner is ");


if (iNumberl > iNumber2 && iNumberl > iNumber3)
Conso le .W ri te Li ne ("Noisy Glue"); // 3
else if (iNumber2 > iNumberl && iNumber2 > iNumber3)
Console.Wr it eL in e ("The Train"); // 2
else
Console.W ri te Li ne ("Whitefire"); // 1

C o n s o l e .W r i t e L i n e ("Would you like to play again (Y/N)?");


input = C o n s o l e .R e a d L i n e ();
}
}

static void TheRace(ref int Num) {


Random rnd = new R a n d o m ();

Num = (int)Math.Round(rnd.NextDouble() * 1000);

static void T i e B r e a k e r (int Numl, ref int Num2) {


if (Numl == Num2) {

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).

E xam p le 2.44. The k ey w o rd o u t.

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;

C o n s o l e .W r i t e L i n e (" L e t 1s have a h or s e rac e .\ n "


+ "To p l a y selec t one of the ho r s e s below");

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 ) ;

TieBreaker (iNumberl, ref i N u m b e r 2 ) ;


TieBreaker (iNumber2, ref i N u m b e r 3 ) ;
T ie Breaker (iNumberl, ref i N u m b e r 3 ) ;

114
Chapter 2: Branches, Loops, and Functions

C o n s o l e .W ri t e ("And the w i n n e r is ");

if (iNumberl > iNumb e r2 && i Numberl > iNumber3)


C o n s o l e .W r i t e L i n e ("Noisy Glue"); // 3
else if (iNumber2 > iNumbe r l && i N umber2 > iNumber3)
C o n s o l e .W r i t e L i n e ("The Train"); // 2
else
C o n s o l e .W r i t e L i n e (" W h i t e f i r e " ); // 1

C o n s o l e .W r i t e L i n e (" Would you like to p l a y a g a in (Y/N)?");


input = C o n s o l e .R e a d L i n e (); }
}

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);
}

s ta t i c v o i d T i e B r e a k e r (int Numl, ref int Num2) {


if (Numl == Num2) {
T h e R a c e ( o u t Num2);
T i e B r e a k e r ( N u m l , ref Num2);

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

E xam ple 2.45. O verload in g a fu n ction .

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
int iNumberl = 0, iNumber2 = 0, iNumber3 = 0, iTotal;

C o n s o l e .W r i t e L i n e ("Please enter two to three "


+ "numbers to be added\n"
+ "If you only have two numbers make "
+ "the third number equal to zero:\n");

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);

Console.WriteLine("The Sum of these numbers was {0}", iTotal);


}
static int Sum(int iNumberl, int iNumber2) {
int iSum;
iSum = iNumberl + iNumber2;
return (iSum);

static int Sum(int iNumberl, int iNumber2, int iNumber3) {


int iSum;
iSum = iNumberl + iNumber2 + iNumber3;
return (iSum);
}

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.

E xam p le 2.46. T h is p rogram d o es n o t o v erlo a d th e fu n ctio n .

using System;

namespace Chapter2 {
class Classl {
static void Main() {
string input;
int iNumberl = 0, iNumber2 = 0,
iNumber3 = 0, iTotal;

C o n s o l e .W r i t e L i n e ("Please enter two to three numbers"


+ "to be added\n"
+ "If you only have two numbers "
+ "make the third number equal to zero: \n");

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);

iTotal = S u m (iNumberl, iNumber2, iNumber3);

C o n s o l e .WriteLine ("The Sum of these numbers was {0}", iTotal)


}

static int Sum(int iNumberl, int iNumber2, int iNumber3) {


int iSum;
iSum = iNumberl + iNumber2 + iNumber3;
return (iSum);
}

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.

E xam p le 2.47. R ecu rsio n .

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;

C o n s o l e .W r i t e L i n e ("\n Enter Your Access Code Now: ");


input = C o n s o l e .ReadLine ();
password = i n t .P a r s e (input);
if (password == 1024) {
C o n s o l e .W r i t e L i n e ("\n Access Granted");
return;
} else
P a s s w o r d ();

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.

Common Errors, Problems, and Pitfalls


1. Symbol com binations such as ==, !=, and >= cannot be w ritten
w ith spaces betw een them (= =, ! =). incorrect and should alw ays
be avoided even if the program seems to work.
2. Do not confuse = w ith = =. Rem em ber = is used to assign a value
and = = is used to compare two values.
3. A ttem pting to use a single equal sign inside an if statem en t will
resu lt in an error.

119
C# and Game Programming

4 While loops do not require a semicolon, but d o - w h i l e loops do


(as in do.. .while (something);).
5. Most compilers don’t recognize nam es beyond the first th irty
ch aracters so be careful w ith long nam es th a t are too sim ilar.
6. Leaving off a closing bracket usually causes several errors. In
addition, forgetting to delete an excess bracket usually causes an
unexpected error.
7. Forgetting to term in ate a W h i l e loop is a prim e exam ple of a
logical/runtim e error. The program does everything it’s told
to do, b u t th a t causes it to become stuck. The solution is sim ply to
cancel the program eith er w ith a Ctrl-<C> or by closing the
executable window w ith the mouse and th en rew riting th e loop to
include an event th a t will end it a t the rig h t tim e. This type of
error is most commonly called an infinite loop error.
8. All values should be initialized before any inform ation is taken
from them , not doing so will resu lt in a corrupted data error.
9. Of course, you still can’t divide by zero, so don’t even try it.
However, if you fear th a t occasionally your d a ta m ight total zero,
you’ll need to te st for th a t resu lt and work around it. This can be
done in m any ways, but the easiest is w ith the i f sta te m e n t
(think about short-circuiting).
10. You cannot increm ent or decrem ent a complex variable. For
exam ple, you w ouldn’t be able to increm ent the sum of two
num bers, e.g., [(x+5)++].
11. One of the m ost common errors is to m istakenly reverse a less
th a n or g reater th a n symbol from inside a loop’s term in atio n
sequence, causing the com parison to never find its m atch: th is is
a typographical error th a t creates a runtim e error (an infinite loop).
12. Did you place a semicolon a t the end of th e first line of an i f
statem en t, for statem en t, or s w i t c h statem ent? Doing so would
indicate to the compiler th a t these lines are blank or null and
your block or single statem en t would not be viewed as p a rt of
th a t sequence.
13. Remember, from inside a function’s definition, you m ust declare
each d a ta type individually as in in t one, in t two; attem p tin g to
include them ju st w ith a comma results in a compiling error.

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. Always use a standard predefined function when possible; they


speed up program m ing task s and increase program portability.
13. The goal of any good program m er is to w rite code th a t can be
reused in several projects. Don’t waste time rewriting the same code.
14. W hen using i f - e l s e statem en ts try to place the most common
occurrence first; this will speed up your program by moving you
to th e right info faster.
15. Converting several i f statem ents into fewer i f - e l s e statem ents
also speeds up program s, since more com parisons can be skipped
and tim e is saved.
16. Some program m ers use brackets to enclose every i f - e l s e
statem ent. I’ll do this on occasion, but I usually leave single
statem en ts as is.
17. It should be noted th a t not every s w itc h statem en t requires a
concluding default statem ent, and th a t these defaults could be
listed a t th e top or anyw here inside the switch statem ent.
However, there are some things to be said about sticking w ith the
standard— in this case, it will make your programs easier to read.
18. You should also note th a t loops based on counters such as the f o r
and w h ile loops will become infinite if th eir m arks are counting
the wrong way or s ta rt after the m ark. These are also considered
infinite loops, bu t can be m uch h a rd e r to find.
19. Always rem em ber w hen asking the u ser for in p u ts such as nam e,
social security num ber... You can echo th a t inform ation to allow
for changes.
20. Be careful w hen com paring real num bers: Remember, 4.001 does
not equal 4.00005, and n eith er equal the integer value 4.
21. Avoid using floating point variables (float and double) to count loops.
22. C#, like C/C-H-, alw ays attem p ts to shortcut a comparison w hen it
is w ritten using an && symbol; th is will save tim e... Thus to
speed up your program s you should try to place the more
commonly false tests first.
23. Some program m ers feel th a t keywords such as b r e a k and
c o n ti n u e violate the stru ctu red program m er’s ideals. These

12 2
Chapter 2: Branches, Loops, and Functions

keywords, however, speed up program m ing task s and are


considered valuable by m any program m ers.
24. W hen it comes to value versus reference use, rem em ber th a t
reference values are faster, b u t value types are safer.
25. Remember, the inline qualifier is autom atic in C#.
26. Try to lim it each function to a single task. If one function requires
a large list of variables, or if it does the job of m any functions,
th en it's probably too big. Remember, the ultim ate goal of the
program m er is to w rite for both reusability and portability.

1. U sing th ree i f statem ents, w rite a program th a t tests two Questions


variables such th a t if it finds th a t the first variable is equal to,
less than, or greater th a n the second, a corresponding m essage is
displayed.
2. U sing the keyword e l s e - i f , simplify the previous program
(Hint: Use one i f sta te m e n t and two e l s e - i f s ) .
3. Using the keyword e l s e , simplify the first program to use one if
statem ent, one e l s e - i f statem ent, and one e l s e statem ent.
4. From Q uestion 3, revise each comparison to include the
compound i f , e l s e - i f , and e l s e statem ents.
5. W rite a program th a t uses a nested if statem en t th a t first asks
the user if he/she has two num bers to compare and th en repeats
Q uestion 4.
6. Revise the program from Q uestion 5 using the o r operator as is
o r 11 y ) .
7. Revise the program from Q uestion 5 using the “and” and the
“not” operators.
8. Find the sum of two num bers using the abbreviated form +=.
9. R epeat Question 8 for subtraction, m ultiplication, division, and
rem ainders.

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

The marble not yet carved can hold the form


o f every thought the greatest artist has.
-M ichelangelo

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

Emulation Layer), which serves as a secondary interface. When our hardware


does not support a certain feature or function, specific device support is given
as a product of a Globally Unique Identifier or GUID. The advantages of using
m anufacture-com posed device drivers include hardw are-independence,
increased performance, and complete access to special features and functions
(see Diagram 3.1).

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

DirectX 9 C# Wizard DirectX9Application2

Project Settings
Specifythe DirectXcomponentsandsupport featuresfor your application.

What graphical component would you like to use?


r Direct3D
r DirectDraw

(• System. Drawing Screen


r Render to PictureBox control
Shot
What adcStional support would you tke to include?
fv Directlnput 3.0
r Audio

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.

Game 1 —Paddle Tennis


For our first game, w ell deliberately keep things simple w ith three objects, one back­
ground image, and an area of a single screen. W ell also restrict our motion and keep the
physics to a minimum, which leaves us with the obvious choices of twin tennis players and
a simple tennis ball. We can create a net using simple graphics, and of course, w ell
include basic sounds for the racket, ball, and cheers of the crowd, but again, all of these
steps should be done in the proper order, beginning w ith the creation of an outline...

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.

E xam ple 3.1. B r a in sto r m in g P ad d le T en n is.

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

Rle Edit View loots Window Help

W' Q& 0 > • Qp 5cwe ’ iS c ff * ?

I n0^E 8l H ew P ro je c t fx ■

Project Types: [ffj


( p Visual Basic Projects
Visual C# Projects m Be!
i l l visual C + + Projects Windows Class Library Windows
i l l Setup and Deployment Projects Appfcation ontrol Library
Control Libra
$ Other Projects

What’ s New
i j | Visual Studio Solutions
% #* i£I
A5P.nct web ASP,NET web web control
Or fine Ccmrnur Appfcation Service library

Screen A project for creating an application wfth a Windows


Search 0*»line
Shot Dcwnloacs ; Name: fcNoM
Web Hosting Location: 8
j C:\DocumentsandSettings\Salvatore uono\My Oocur Browse...
3.1. Ml P tvfllr ; Project w i be created at C:\. ..jSahratore Buonol,My Doaiments\«sual Studo Projects\Chapter3.

TPMorjt Help
0 Bufd EitotL . *X
v Description
Cfckhereto add* task

cj Tasklist] E l Output i 3 Search Resets for Exception j

File £dt View Project Bufcl Debug Data Fgrroat Tods Window Help

§] - £3 - air y & ► fehug - g p Score

.
Start Page Form I .cs [Design] |

Screen
Shot
3.2.

134
Chapter 3: Writing Games

I Chapter3 - Microsoft Visual G?.NET fdesip.nl Form! .cs* BEE


Ffe £d* $ew Project guid Qebug Ioo)s ^ndow fctefp

' gp * & ' 0? B 0 %^ - m’ ► Debug * ap Score V « of * ?

*>. m&'i 'i *%%%.


% cert Pag* j Forrai .ct[0es»$flj|* F om al.c**) 4 X

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

21 Task List 1 E l Output j jjflft Search Res.#? for Exception ;


Ready

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

~b<iptor3 M k ro s o ft '/is u a l ( tf.N E T i d e sign ] f o n u l c s*

File £<» View Project guUd Cebug loo k ^hd ow fcjelp

53 - £g* c£ a flP X Us g* » ■ •JD - c; ► 0rt>ug

% Start ftsge j Foant nxi


jtj s ' ' : Categories: IffSl
“ 3
B vising
using
Syst
Syst H
| Visual C++
Script

HTMLPage
n
Frameset
using Syst
using Syst
Screen using Syst
using Syst
Shot StyleSheet XMFie XMLSchema
j nconespoce
3.4. (
/// <*
/// Sv
/// <
p u b li
{ in empty bitmap Me.

j £
Task List - 0 Buid Erri

* here to add a new task

2JTM
kLutIB Search fuwdt* for Exnptton |

“ 1 " 1 ~

| * S ta n -JCtf43.de»: Macrsoi Chapter 3 - Mkosoft ... < 3 IS PM J

Clwpti>r3 - Micrnsnft Visual Ctf .Nf T [rinsigr'] RHnv»p1


FIs £dit View Project Quid Qebug look Image tfjndwv tMP
S l- 'E j- tfO flP * » M uq ~ * score
£ <?% E tf ^ ^ A a ■ ■ O• » o • •
Start Pag* Forml.cs [Design]* | Forml xs4 Bitm ap 1 1

Si
sKHHHSHfc
Screen
Shot
3.5.
pf|||I i l
.-.{SSSJSSfj
SSffiimprrttrI
ntHmgpj

TackUt - 0BuidError tacksluwn (fkarad) » X


1 £? Description Fie Une
Clkk here toaddener*task

v)TaskList| 3 Output 2 ) Seoich Results for Exception j


6: 1 Magnification 1!

S E d lt J C#-*. Joe. • i-.-iuxtfi '.hepter x • 'K iostlr ~<1 i

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).

06 £<ft tfew Project guM gebog loots Image Wndow Hot

§] - 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

□ i,H .rP-'-.-yp,;-; t-tesS S ®


PliiS? ii itfci j,.4i-Ja
1 : • ; ; : : .u . :
aiSi
: ::
Screen
lit , ■
Shot
w SSSiJS . . . < t ,, < > 1-! 3.6.
jj , , ->
s-
«■,‘K...-r ;
f J! gffi*
i r - i,- , 4 , £,,-*S!
Task Ust - 0 Build Error tasks shown (fftered)

* Ockhers to add a w ; task

21 Tasklist] j ] c<<mk j i & Search ResUts for feoption :


~fa >92,8 ;|10x0

m
Efe 0K View Project gold gebug loots Image Window Help

• 43 ’ • ► Ortug - j# Score

fa Q J a <3feP -1(7]^ ^ x 7 A □ » r n o m m a m rn * - :fU


^ C o lo r s 9 X (Cesrgnj; FormUs j Classl.cs | C la s p s j Class3.cs j P a sses j Ciass5.cs j TennfeSal.brop j f1ayerl.bmp Ptayet2.bmp | < >

Screen
Shot
3.7.

21 Tasklist 1 HI Output l i f t SearihRssufcs for Eaceettoo ;


Ready

- J C#42.<toe>M*«tt»K...

137
C# and Game Programming

Tenni; Microsoft Visual C#.NET f design! Tennis8aU.bmp

Fife View fro je c t gebug lo o ts Im age Window fcietp

g3*|3 "Q*8 6? * %i <P- 1 ►


Debug
■■!&%£>' [£]<*^ \ 5 A a i i O i
% Colors J? X

mm
mm

8.| mmm
¥ mm '
mm

Screen
Shot
3.8.

Task le t - 0 Bwkl Error tasks shown (fkered)


’ < Description

2 ) Task list 1 n p a p * iB s e a rd iS e s u ts fo f Exception j

'FT* s ta n fSfcws***.. >. Terras-Microsoft

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).

E xam p le 3.3. T w o -d im en sio n a l m ovem en t.

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

Exam ple 3.4. M ovem ent o f the ball.


Two-Dimensional M o vement

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).

E xam p le 3.5. A lg o rith m for P ad d le T en n is.


1. C reate a new Windows Application Project (Note: do not confuse
the Windows Application setting w ith th a t of the Console
Windows Application setting). H ere we’ll also w ant to use “using
System .Drawing;” and “using System.W indows.Forms;” The
D raw ing nam espace will allow us to access G raphics and
Bitm aps, while the Form s nam espace will allow us to use
keyboard, mouse, and p ain t functions. We’ll also w ant to give our
project a notable nam e as in “Tennis.”

139
C# and Game Programming

2. At the top, we’ll include constants for changeable references such


as size, counts, and media.
3. We’ll w ant to include graphic buffers (buffers are used to flip-
pages, which is a very sim ple wray of reducing flickering), m enus,
and links to classes nam ely the gam e classes listed on the CD-
ROM. (Note: classes will be defined in chapter five).
4. As we build, we’ll w ant to place all of our code into regions - each
region relating to a p articu lar aspect of the game.

Game loops are real-tim e loops th a t are not dependent on th e users


action, th u s th e re ’s no grantee th a t th e loop will ever end. However,
at the sam e tim e w hen the loop does end, it should end in a
stru ctu red m anner and it should give the player the option of playing
again or quitting.
5. Setup & Initialization
a. Load images: Here we’ll w ant to use jpegs (also w ritten as
jpg). Jpegs use only a faction of th e memory required by
bitm aps (bmp) w ith only a m inor loss in quality (Note: The
DirectX versions of these gam es require the bitm ap form at,
using .jpg or any other form at will cause an error.) As far a
GDI+ is concerned, you can switch betw een d a ta types ju st by
changing the extension, provided you have a file stored in that format.
b. Set players/characters position: We’ll have to choose startin g
positions for the players. The players, as well as the ball will
be reassigned throughout the game. The Net has a fixed position.
c. Define player restrictions: The Ball deactivates as it leaves
the screen, bu t the players do not, th u s we’ll have to prevent
them from leaving the screen. We’ll also w ant to stop the
players from passing through th e net.
d. Define M enu: There will be th ree game choices, two-player,
single-player, and demo; the m enu should reflect those choices.
6. P ain t M ethods: W rite two functions w ith the first being used to
setup the buffer and the second being used to display. We’ll also
w ant to include an introduction for w hen the game is inactive,
the characters to be displayed being Players, Ball, Scoreboard, and Net.

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

reached. Here, w ell also use the two-point rule (explained in


coding).
13. Ask the player(s) if they w ant to play again. Remember a good game
loop should always allow the player(s) the option of playing again.
14. Tennis AI: Player Left: Lim ited to vertical m ovem ent (one­
dim ensional), Player Right: Complete two-dim ensional
m ovem ent. (Note: Rem em ber to m ake the com puters choices
som ew hat faulty).
15. Event Processors: Timed Events, Single Player, Two P layer and
Demo, these should all be tied to th e s ta rt m enu, and should not
be m ade changeable except when sta rtin g a new game.
16. W rite a function to lim it the area in which the players can
traverse. This is our first case of collision detection and as such,
we’ll m ake it simple. The characters our placed on the screen
based on preset location. W hen the player inputs a movem ent,
the program processes th a t m ovem ent by adding or subtracting
one u n it of distance from th a t p lay er’s location. This distance is
based on a general un d erstan d in g th a t th e first space of th e first
line is coordinate (0, 0). Since the player is now confined to a
m athem atical grid, we can “lock him down” by not allowing those
values to increase or decrease beyond a certain point. The ball
works in a sim ilar m anner w ith its deflection being based on a
change in p a th ra th e r th an resetting its location.
17. Game Over: Ending the gam ing loop in our case m eans ending
th e gam e and retu rn in g to the m enu portion, th is th en allows the
u sers to eith er quit the program or continue into another game.

When thinking of how we might implement those functions using a C# model it


becomes obvious that the most direct solution would be to convert those tools
into methods (methods are functions that are called from the vantage point of
a class). Expanding our classes to include multiple tasks also gives them a
greater level of control, as well as a more practical sense of reusability. (See
Diagram 3.2)

142
Chapter 3: Writing Games

Paddle Tennis

.N et Library

Game Namespace

Paddle T ennis Class

Initialization Controls
Diagram
3.2
Paint A.I.

Keyboard Events

M ouse Game Over

J oystick Sub-Class

Displaying Graphics Using Native C++


Once we’ve completed our drawings and have a basic sense of motion, we’ll w ant to include
the appropriate coding such as the visual param eters, setups, system calls, etc. The original
coding for these games was w ritten in the good old console version of C++, where animation
m eant repositioning block characters using a COORD command (which stood for coordi­
nates as in the x,y, or Cartesian, coordinate system) and then setting our window to that
position using the “SetConsoleCursorPosition” function. T hat also m eant th a t we had to
repeatedly remove the previous image and redisplay the new characters to actually see the
anim ation, but th a t was then and this is now.

Displaying Graphics Using C#


Despite the advances, we’ll still need to understand the basic C artesian coordinate system,
at least as it pertains to our screen. Here the x andy coordinate values sta rt as zeros at the

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.

E xam p le 3.6. C a rtesia n c o o r d in a te s.

(0, 0) > > (40, 0) > > (80, 0)

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).

Displaying Graphics Using DirectDraw


The H ardw are Acceleration Layer (HAL) is comprised of a host of sub-HAL compo­
nents, these components reflect the different aspects of DirectX e.g., DDHAL (DirectDraw
H ardw are A cceleration Layer), DIHAL (D irectln p u t A cceleration Layer), DSHAL
(DirectSound Acceleration Layer), etc. DirectDraw as its name implies allows for direct or
near direct access to our video hardw are. The DDHAL can be built into the display driver
or included as a Dynamic Link Library (DLL). We as program m ers do not interface di­
rectly with the DDHAL; ra th e r our requests are delegated through the DirectDraw com­
ponent (see Diagram 3.3).

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).

Example 3.8 implements a simple try-block exception handler (Exception


H a n d lin g is e x p la in e d in C hapter 5), th is is done to avoid th e
WasStillDrawException, which can occur when flipping between buffered and
primary graphics, as well as the InvalidRectangleException, which can occur
when a character moves off screen. Both exceptions are considered insignificant
and do not e x is t in D irect3 D . A lter n a tiv ely , we could h ave used a
Microsoft.DirectX.DirectXException.IgnoreExceptions 0;•

145
C# and Game Programming

Introducing Object-Oriented Programming


In order to u n d e rsta n d th e concepts behind th e developm ent of object-oriented p ro ­
gram m ing, we m u st first discuss th e principles behind its predecessors, such as top-
down design, stru c tu re d program m ing, and m odular program m ing. Top-down design
is a lin e a r approach to program m ing w here you s ta r t a t th e top and w ork your way
down, w hereas stru c tu re d program m ing is m ore of a system atic approach to problem
solving based prim arily on the idea of divido et vinco (divide and conquer). This process
allowed the program m er to develop larg e r and more complex program s, b u t it did not
initially allow for reuse w ithout m odification. S tru c tu re d program m ing com plem ents
top-down design and lead to a concept known as generic coding. The combined power of
stru c tu re d program m ing and generic coding also allow ed for th e restrin g in g of func­
tions to solve additional problems. M odular program m ing developed as an expansion to
stru c tu re d program m ing, allows for th e linkage of files and generically coded subpro­
gram s, but th is too fell short of m eeting the dem ands placed on today’s program m ers.
O bject-oriented program m ing is both a collection of th e above techniques and a
progression from object-based program s to object-driven program s. G enerically w rit­
ten stru ctu re, and th en classes, becam e the em phasis, and objects becam e th e guiding
tool used by m ost program m ers. C lasses took on a new approach th a t included friend
and m em ber functions (and now w h at is referred to as m ethods) to create a generic
fram ew ork th a t can be applied to a m u ltitu d e of task s. In h erita n c e w as developed
along with a slue of new methodologies and concepts. In this new fram ew ork, variables
are often replaced by class m em bers and functions by m ethods. W hile th e coding th a t
defines these objects won’t actually be discussed u n til C hapter 5, the practical applica­
tions th a t allow for th eir use will be im plem ented here. This is possible though the use
of the black box m ethod applied to both m em bers and m ethods (again, see C hapter 5 for
details).

Adding Files to Our Projects


To properly im plem ent the previous program , we m ust first tra n sfe r its supplem ental
files to the ap p ro p riate m ain or subdirectory. This can be done th ro u g h a sim ple copy
and paste procedure as explained below.

146
Chapter 3: Writing Games

Adding Files to our Projects:

1. Locate the files required by our project (this book’s CD-ROM’s


source code files referenced in the previous sections). (Note: The
necessary files are bundled as part of Chapter 3’s “Anim ationTestl”).
2. Select and copy the required files as shown in Screen Shot 3.9
(this will include A nim atedlm age.es through Walls.cs,Playerl.bm p,
Player2.bmp, TennisBall.bmp...).
3. Open the appropriate directory and paste those files to th a t
directory (this is the directory usually created by the compiler as
p a rt of your cu rren t project - see Screen Shot 3.10).

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

Places Files of {ype: bit Files (*.*)

Look in: j rM. Chapter3A1


H S3 Si' Tools -

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).

f»e view Project guild getwg loots window fcWp


g p Nextlevct

Pi %Is AS iwiw 1 1
H StartPac Add E xistin g Item • Chapter3A1
Chapter3A1 if X

J jP = lock ft: Chapter3Al “3 m ' G O ’ to o u - I


iptcr3Al1(1 project)
r Q tJD 3A1
m ___
** ! AssemblyInfo, cs’
rences
mblylnfo.cs
History
Screen ElCfctisJLai View ►
TFlctoss2.es i2.CS
Arrange Icons By >
Shot 2 b
fy1Cbss3.cs Refresh
O.C5

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

Real-Time Game P rogram m ing Basics


In the older C++ model,we used simple commands like KbhitO and getchO, which
were the real-time equivalents to both cin » and scanfO- Since C# also allows for
quick and easy access to both console and windows-type applications, we can progress
quite easily into OnKeyDown and OnKeyPress type examples. These Windows
commands allow for multitasking, or what beginner game programmers might call
basic real-time programming. The term real-time refers to the continuation of actions
within a particular time frame without regard for the users’ response.

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) : ©

Directlnput: the Keyboard

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

As p art of creating a D irectlnput keyboard reference, w ell need to include a device


assignm ent. Device assignm ents are generally listed as private class members. W ell also
w ant to include a tim er reference, for example:

using Microsoft.DirectX.Directlnput;

private M i c r o s o f t .Di re c t X .Di rectInput.Device keyboard = null;


private S y s t e m .W i n d o w s .F o r m s .Timer Keyboard;

Next we will need to include a reference to th a t tim er, as well as an event handler:

t h i s .Keyboard = new Sy st em .W in d ow s.F o rm s.Timer (t h i s .components);


this.Keyboard.Tick += new System.EventHandler (this.Keyboard_Tick);

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.

Erasing Residual Images


Erasing residual images is an im portant step in the creation of the illusion of anim ations;
each character m ust be erased before its tem poral counterpart can be displayed. This pro­
cess is usually handled through the invalidation of a rectangle or defined area. The actual
work or process is handled by Windows, but the referencing of th a t system is done from
w ithin our programs. Surprisingly enough, we’ve already included an invalidating refer­
ence, w hich is almost plugged in without thought. Yet there should also be a set of cautions

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.

Remember, the source code is included on the CD-ROM.

Collision Detection: The Players’ Boundaries


Now th a t we have a p layer who can roam aro u n d our screen, we’ll w an t to give him
some lim itatio n . A fter all, we cannot have him w andering off now, can we? The code
used to stop our c h a ra c te r’s excess m otion is actually quite sim ple, ju st a sw itch
sta te m e n t, and some in crem en tin g and decrem enting operators. These sta te m e n ts
will probably seem a b it complex and possibly confusing, b u t t h a t ’s because w e’re
also using th em as p a rt of both our user-defined and class-based m ethods (just r e ­
m em ber th a t th e principles are basically th e sam e). If you feel you need a little bit
m ore of an explanation, ju st have a look a t th e next exam ple. H ere, w e’re looking a t
a m ethod th a t is included as p a rt of our first character-b ased class. W hen we d e­
clare an object such as P la y e rl, Player2, or even the ball, w e’ll gain access to th a t
m ethod. Now, w hen we w ant to test for those p aram eters, we’ll simply call th a t m ethod
by w riting it out as: O urO bject.D eflectPlayers (), OurObject.DeflectBall. Alternatively,
we m ay w ant to read a value such as OurObject.V ector.ReadV alue (), or w ith the key­

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).

E xam p le 3.11. P la y er b o u n d a r ie s from P la y e r.c s : A n im a te d lm a g e.e s


using System;
using S ystem.Drawing;
using System.Wi ndows.Forms;

using GameClasses; // Our common utility classes


namespace Games {
public class PaddleTennis : S y s t e m .W i n d o w s .F o r m s .Form {
Player playerL; // Object representing the left player
Player playerR; // Object representing the right player

// 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 );
}
}
}

Collision Detection: The Ball in Motion


The next few steps m om entarily abandon the player and p u t our focus on th e ball. The
ball uses the sam e c h aracter-b ased class and m ethods as th e players, b u t w ith a few
m inor changes. The ball should also be deflected by th e walls, b u t th is tim e we’ll w ant
to use those w alls to im plem ent changes in th a t object’s direction, which, of course,

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.

E xam p le 3.12. N u m eric k ey p a d d ir ec tio n s..

Upper Left 7 8 9 Upper Right


Left 4 5 6 Right
Lower Left 1 2 3 Lower Right

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).

E xam p le 3.13. N u m eric r e p r e se n ta tio n o f th e b a ll’s d e fle c tio n .

A lthough technically we did not m athem atically m ap out the ball’s


path, we did m anage to give the ball a close rep resentation of w hat
would have happened in an actual two-dim ensional elastic collision
(an elastic collision being one th a t does not a lter the shape of the
objects impacted).

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.

x When multi-rendered scenes exist simultaneously, the adverse effect is a display


^ \ error referred to as tearing. To avoid such an effect, graphical output is often
buffered and flipped in a single reference.

Collision Detection: Deflecting the Ball


The next thing we’ll w ant to do with our players is give them the ability to deflect the ball.
This will become ever more useful once we’ve covered how to combine the two. In the first
method, we’ll discuss changing the ball’s direction using the same principles covered in the
previous section, but with a different order of deflection. Anew order of deflection is necessary
to keep the players’interest by providing a wider variety of patterns to perceive. In addition,
as was mentioned, we’ll also w ant to plug in some random paths, which will allow for other
less conditional patterns, but we’ll get to those in a moment.
Our first step will be to plot our players’ p atterns of deflection. These, as you should
remember, are the p attern s th a t the ball takes after it collides with an object. Once again,
we’ll use the numeric keypad/ 10-key system as our point of reference (see Example 3.15).

E xam p le 3.15. N u m e r ic a lly p lo ttin g p la y e r s’ p a tte r n s o f d e fle c tio n .

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).

E xam p le 3.16. P la y e rs d e fle c tin g th e ball.


public void H i t T h e B a l l O {
if (!t h e B a l l .isActive)
return;

// There are three possible directions, so pick a random number


// from 0-2.
Random rnd = new R a n d o m ();
int seed = rnd.Next (3);

// If the player serving is on the right the possible directions


// are 1, 4, and 7 (seed * 3 + 1 )
if (theBall.imagePosX > t h i s .C li en tS iz e.Width >> 1) {
if (th e B a l l .direction == A n i m a t ed lm ag e.WEST ||
th e B a l l .direction == A n i m at ed lm ag e.NORTHWEST ||
t h e B al l.direction == A n i m at ed lm ag e.SOUTHWEST) {
return; // We've already hit it! Can't hit it again
}
t h e B a l l .direction = seed * 3 + 1 ;
} else {
if (t h e B a l l .d i r e c t i o n == A n i m a t e d l m a g e .EAST ||
t h e B a l l .direction == A n i m a t ed lm ag e.NORTHEAST ||
t h e B al l.direction == A n i m a te dl ma ge .SOUTHEAST) {
return; // We've already hit it! Can't hit it again
}

// possible directions are 3, 6, 9 (seed * 3 + 3 )


t he B a l l .direction = seed * 3 + 3 ;
}
t h e B a l l .A n i m a t e ();
U t i l s .PlaySound(Utils.C o n f i g [" S ou nd .R acket"]);

155
C# and Game Programming

A Few Minor Details:


Scores, Speed Settings, and Additional Graphics
Now th a t w eve plotted the characters’ motions, including our boundaries and pattern s of
deflection, and since we’ve already put together a working example of both the players and
th eir ball, it would seem th a t there would be little else to do but to put all these pieces
together and call it a game. This, unfortunately, is not the case, since there are still
several issues th a t need to be addressed. For example, we’ll need a way to im plem ent our
players’ scores and a way to term inate the game when a player reaches a certain score. In
addition, we’ll also need to discuss adjusting the ball’s speed, adding in the net, and con­
trolling the serve. Not to worry, these are all relatively simple issues and we’ll get back to
the fun stuff momentarily.

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).

E xam ple 3.17. K eep in g sc o re —ste p one.


p l a y e r L .score = 0;
p l a y e r R .score = 0;
int scorel = p l a y e r L .s c o re ;
int score2 = p l a y e r R .sco re ;

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).

E xam p le 3.18. K eep in g sc o re —ste p tw o.


playerL.score++;
playerL.score— ;
playerR.score++;
playerR.score— ;

156
Chapter 3: Writing Games

Displaying scores is ju st a m atter of referencing our d a ta in the correct m anner. This


tim e, in addition to retrieving th a t data, we’ll also need to convert it into a string value
before attem pting to display it (see Example 3.19).

E xam p le 3.19. K eep in g sc o re —ste p th ree.


public void DoPaint(Graphics g) {

// Draw the scores


Font Normal = new Font("Time New Roman", 14, Fo nt Style.B o l d ) ;
g .Dr aw S t r i n g ((playerL.s c o r e ) .T o S t r i n g (), Normal, myBrush,
new Rectangle(new Point (4 * SCALE, SCALE),
new Size (24 * SCALE, 12 * SCALE)));

g .Dr aw S t r i n g ((playerR.score) .ToString (), Normal, myBrush,


new Rectangle(new P o i n t (16 * SCALE, SCALE),
new Size (24 * SCALE, 12 * SCALE)));

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 ple 3.21.


// Start the game
gameState.currentState = GameState.St at e.Started
// Stop the game
gameState.currentState = GameState.S t at e.Stopped

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).

E xam p le 3.23. S e ttin g th e g a m e’s sp eed .


GameState gameState = new G a m e S t a t e ();

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

Exam ple 3.24. D raw ing the net.


// Draw the "net". 5x5 square spaced 15 apart
Brush myBrush = B r u s h e s .Yellow;
for (int Y = 0; Y <= t h i s .C l i en tS iz e .Heigh t; Y += 15) {
g .FillRectangle(myBrush, 12 * SCALE, Y, 5, 5);
}

Controlling the Serve


F irst, we’ll need to develop a random num ber gen erato r th a t sets th e in itia l p a th of
our projectile (the ball). Second, we’ll need to keep tra c k of the projectile’s location
and set up scenarios th a t allow for the ball to sw itch sides. For convenience, we’ll also
w ant to bundle these procedures into a sim ple function (see Exam ple 3.25).

E xam p le 3.25. C o n tro llin g th e serve.


public void S e r v e () {
if (!t h e B a l l .isActive) {
th e B a l l .isActive = true;
Hi tTheBal1 () ;

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

D is p la y T e n n is B a ll = n fj1 Aquam arine Sam es.

t h i s . A u t o S c r o 1 l H i n S i [?§f, Azure .Si ce:


Screen
........................................................................eS * Beige
[ffj1 Bisque
Shot
: [?§? Black 3.12.
Ef? BlanchedAknond
e£* Blue d

E xam ple 3.26. U sin g c o lo r to sp e c ify sh ap e.


protected override void O n P a i n t (PaintEventArgs e) {
Graphics g = e.Graphics;

Brush yellowBrush = B r u s h e s .Yellow;


g .FillR ec ta ngl e(yellowBrush, 390, 100, 25, 25);

Pen yellowPen = Pens.Yellow;


g .DrawEllipse(yellowPen, 390, 200, 25, 25);
}

16 0
Chapter 3: Writing Games

y_ ____ x1 = ImagePosX, y1 = ImagePosY

x2 = lmagePosX+SCALE/2,
y2 = ImagePosY+SCALE

x+

D iagram 3.4 The P ad d le

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.

Adding Sounds Using Windows Multimedia


Another important aspect to game programming is the use of sounds. Sounds can be used to
enhance the overall quality of our games, and for other minor tasks such as system notifications,
popup ads, and virus alerts. While the recording of our sounds won’t be handled through the .Net
compiler, the storage for such sounds should be made part of any current project or at least as
part of a central media base. There are two factors involved in declaring sounds: the Windows
reference, and the executing statements (see Examples 3.27).

161
C# and Game Programming

E xam ple 3.27. W indow s m u ltim e d ia sound.


public class AnyClass : 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 dwFlags);

public void AnyMethod () {


Pl a y S o u n d (@ " C :\SourceCode\Wall.w a v " , 0, 0);

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).

Remember, you can reposition these commands to create sounds anywhere in


your programs, but be careful not to over use them. Multiple sound references
can disrupt the game flow and cause other minor errors.

Adding Sounds Using DirectSound


DirectSound is the DirectX alternative to using Windows Multimedia to produce sound.
Here we’ll mimic the initial steps used to include DirectDraw and Input e.g., adding a
nam espace, including variables, setting a cooperation level, etc. However, ra th e r th an
creating a single D irectSound function (as compared to OnPaint, Keyboard Tick,
etc.), we’ll apply our techniques as p art of our gaming model. DirectSound has two types of
buffers used to hold audio data; the stock Buffer object and its derivative the SecondaryBuffer
object (see Example 3.28/Complete code listed on CD-ROM Example 3.28).

162
Chapter 3: Writing Games

Exam ple 3.28. Sound Test I.

using Microsoft.DirectX.DirectSound;
using Buffer = M icrosoft.DirectX.DirectSound.SecondaryBuffer;
using Microsoft.DirectX.DirectInput;

We’ll begin by including the D irectSound namespace; we’ll also have to


rem em ber to add the appropriate DLL. Sound also requires a secondary
buffer, as well as a device variable, we’ll use sound = null;

private M i c r o s o f t .D i r e ct X.D ir ec tlnput.Device keyboard = null;


private Mi c r o s o f t .D i r e ct X.D ir ec tSound.Device sound = null;
private SecondaryBuffer SoundBuffer = null;

It is im portant to qualify device references, as the combination of


DirectX nam espaces will cause conflicts. The cooperation level can be
set to Norm al, Priority, or W rite P rim ary (I’ve set th is exam ple to
priority to include the highest level of performance).

// 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).

for (Key k = Key.Escape; k <= K e y .Medi aS el ec t; k++) {


if (state[k] && k == Key. Sp ac e) {
try {
SoundBuffer = new SecondaryBuffer ("..\\..\\Racket.wav", sound);
SoundB uf fe r.Play (0, BufferPl ay Fl ag s.Default);
}

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).

Table 3.0. S ou n d M ethod s an d P r o p e r tie s.

Adding in the Mouse


A nother in te re stin g fe a tu re to add to our gam es is th e little object sittin g to th e side
of our keyboards (yes, I m ean th e m ouse). The m ouse w as in v en ted in th e 1960s by a
m an nam ed Douglas C. E ngelbart of Stanford R esearch In stitu te (SRI), and la te r p u t
to use a t th e Xerox Palo Alto R esearch C e n te r (know n as PARC) as p a rt of th e firs t
G raphical U ser Interface (or GUI). The m ouse w as also m ade popular by Steven Jobs
w ith the release of a prim itive type of com puter known historically as the M acintosh...
The basic controls we w a n t to w ork w ith include th e O nM ouseU p, O nM ouseDow n,
OnM ouseM ove, and th e O nM ouseW heel (Note: th e OnM ouseW heel also req u ires an
In telliM o u se,a specially designed th re e b u tto n m ouse m a n u fa c tu re d by M icrosoft).
The two key functions w e’ll work w ith are OnM ouseM ove and OnM ouseDown events,
b u t th e o th er two can be applied in b asically th e sam e m anner.
Note: We’ll also w a n t to use th e x, y co o rdinates to m a rk th e g rap h ic al p o sitio n ­
ing. The c o n sta n t 341 is used to re s tric t a c h a ra c te r ’s m ovem ents horizo n tally ; no
v e rtica l re stric tio n s are req u ired , since th ey w ould not affect th e lim ita tio n im plied
by th e ru le s of th e gam e. One should also note th a t th e se m ovem ents w ould not be
u p d a te d u n less th e b all is also found to be in m otion; th is is done to reduce screen
sta tic , or flickering th a t is caused by excessive u p d a te s (see E xam ple 3.29).

164
Chapter 3: Writing Games

E xam ple 3.29. A d d in g in th e M ouse

S tep 1. M arkin g th e m o u se ’s p o sitio n .

// The player on the right "follows" the mouse


protected override void OnMouseMove(MouseEventArgs e) {
C u r s o r .Current = C u r s o r s .UpArrow;
// Demo mode can't allow interaction from user
if (gameState.currentMode == G am eState.Mode.Demo)
return;

if (gameState.currentState == G a m e St at e.S t a t e .Started) {


p l a y e r R .imagePosX = e.X;
p l a y e r R .imagePosY = e.Y;
}
}

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).

S tep 2. G ivin g a p la y er th e a b ility to serv e th e ball.

protected override void OnMouseDown(MouseEventArgs e) {


// Demo mode can't allow interaction from user
if (gameState.currentMode == Ga m eS t a t e .M o d e .Demo)
return;

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

S tep 3. S h o w in g and h id in g th e cu rsor.


C u r s o r .Hide ();
C u r s o r .Show ();

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: The Mouse


Here, we’ll w ant to replace the GDI+ mouse model w ith the D irectlnput version. As with
the DirectX Keyboard, the DirectX M ouse requires several initializing steps before the
actual mouse function can be accessed. Set up includes a device assignm ent and tim er
reference, as well as two Boolean references, namely M ouselnquire and MouseOverride.

// Directlnput
private Mi cr os of t.DirectX.DirectInput.Device mouse = null;

private Sys te m.Wi n d o w s .For ms .Timer Mouse;


bool MouseOverride = false;
bool Mouselnquire = false;

Mouselnquire and MouseOverride are user-defined variables; th eir purpose is to test


for mouse accessibility on the part of the user, the u ser’s options being to disable the mouse
when joystick or even keyboard play is desired. We use Mo use lnq ui re to m ake our
inquirer and Mous eOv err ide to reta in the choice m ade by the player, e.g.:

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:

this.Mouse = new S y s t e m .W i n d o w s .F o r m s .Timer (this.components);


th is .M ou se .Tick += new S y s t e m .EventHandler (this.Mouse_Tick);

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

Exam ple 3.30. D irectlnput: the Mouse.


private void Mouse_Tick(object sender, S y s t e m .EventArgs e) {
mouse = new Micr os of t.DirectX.Directlnput.Device(SystemGuid.Mouse);
MouseState mouseData = new MouseState ();

m o u s e .SetDataFormat (DeviceDataFormat.Mouse);
mouse.Acquire ();
m o u s e .Poll () ;

// Get the current state of the mouse device.


mouseData = m o u s e .CurrentMouseState;

if (MouseOverride) {

byte [] buttons = m o u s e D a t a .GetMouseButtons ();


if (0 != buttons[0] && !t h e B a l l .isActive) {
Serve ();
}
}

Directlnput: The Joystick

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

public class AnimationTest : Sy s t e m .W i n d o w s .F o rm s.Form {


// Directlnput
private M ic ro s o f t .Dir ec tX .DirectInput.Device joystick = null;

public JoystickState JState = new JoystickState ();


private Sy st em .W i n d ow s.F or ms .Timer Joystick;

Next we will need to reference the timer, as well as an event handler:

t h i s .Joystick = new S y s te m.W i n d ow s.For ms .Timer (this.components);


t h i s .Joystick.Tick += new S ystem.EventHandler (t h i s .Joystick_Tick);

J o ys tic k.Start ();

Finally, we’ll need to include a call to sta rt our joystick and the function used by our game
(see Example 3.31).

E xam p le 3.31. D ir e ctln p u t: th e J o y stic k .

private void Joystick_Tick(object sender, Sy s t e m .EventArgs e) {


foreach (Deviceinstance instance in Manager.GetDevices(DeviceClass.GameControl,
En umDevicesFlags.At ta chedOnly) ) {
joystick = new Microsoft.DirectX.Directlnput.Device(instance.InstanceGuid);
break;
}

if (joystick == null) {
retur n;
}

joysti ck .SetDataFormat (DeviceDataFormat.Joystick);


foreach (DeviceObjectInstance d in joy st ic k.Ob je ct s) {
if ((0 != (d.Objectld & (int)DeviceObjectTypeFlags.Ax i s ))) {
j o y s t i c k .Proper ti es .SetRange (ParameterHow.ById,
d.Objectld, new InputRange (-1000, 1000));

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

i f (-400 < JState.X) {


playerR.direction = Animatedlmage.WEST;
Joystick = true;
}
else i f (-500 > JState.X) {
p l a y e r R .direction = A n i m a t ed lm ag e.EAST;
Joystick = true;
}

if (-600 > J S t a t e .Y) {


p l a y e r R .direction = A n i ma te dl ma ge .SOUTH;
Joystick = true;
}
else if(-500 < JState.Y) {
playerR.direction = A n i ma te dl ma ge .NORTH;
Joystick = true;

if(the Ba ll .isActive == false && ga me S t a t e .currentState !=


G a me Sta te .S t a t e .Stopped) {
byte[] buttons = J S t a t e .GetButtons ();
foreach (byte b in buttons) {
if (0 != (b & 0x80)) {
Serve ();

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

€hopter3M enu& * M ic ro s o ft Visual C #,N £T [d e s ig n ] - Tor m l.e s [D e s ig n ]* jf$ < |

Ffe £<* tfovf Project guild fcebug Dflto loo b ^ndow yelp

S 3 - S i - 6? OOP ■ m - <P - G * k Debug - £# ^ - 3 S? * ?

! * | » ~* « S* « & s :> -% so-. « : « * ® ! £ *; it a: >: $ % % „

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

bofi V isual C*'.NCT [ d e s ig n ] • f u i i t i l . c s [D e sig n ]*


Ole CdR view groject gufel fietxig Oflta loots g r kJow Qelp

W * & * a tip «*. £"■ ' V* > - j# Hand


• «j T %fjfc .

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 ;

*****...................... ...........................................................................: ............................. .............................

| - start ■Mirrrwon. Chapter^Menur - Mk. fvWtns.hmfi - Rwit «:rviPM J

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).

File L<* tfew eroject Buto £«bug D *a lock filndow tWP

U -- f t X 5fe f t | o . c 4 3 ' ► Debug - band ': p is * # ?

<*> m | 9 <■ & «>


€ 0 3 3 I * * ! . S?': I i f ! §? « |s § % > *
Toofeox a XI Start P«g«> F o rm l.cf [D«*»gn] j ParmJ.C:
Data

^ 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

3 Tasklist ■0 Output | £4? Search Results |


Ready
_ r _ _ r _ . ..... , '• ^ I
J * S f 3 /1 doc - Mtresoft... ChapterShtenus - r-Sc. . Ip

- 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.

Task L is t-9 BuM Error tasks shown (ftered) 0 X


! V Description Fte Une "f
Grek h e re to add a rsew task
J t > expected C:\D ocum entsand ...Chaptef3M enus\Fcrm l.cs 39
53
3
Ready
Task Ust f i§ O utput: Search aesuks 1
........... !|
m---

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.

E xam p le 3.32. C reatin g a te x t m en u.


using System;
using S y s t e m .W i n d o w s .For ms ;

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 ();
}

#region Windows Form Designer generated code


private void InitializeComponent() {
t h i s .mainMenul =new S y s t e m .W i n d o w s .F o r m s .MainMenu ();
t h i s .menulteml =new S y s t e m .W i n d o w s .F o r m s .Menultern ();
t h i s .menultem2 =new S y s t e m .W i n d o w s .F o r m s .Menultem ();
t h i s .menultem3 =new S y s t e m .W i n d o w s .F o r m s .Menultern ();
t h i s .menultem4 =new S y s t e m .W i n d o w s .F o r m s .Menultern ();

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";

t h i s .ClientSize = new Sy s t e m .Dr a w i n g .Size (292, 266);


this.Menu = t h i s .ma in Me nu l;
this.Name = "Forml";
this.Text = "Forml";
}
#endregion

[STAThread] static void Main() {


A pp l i c a t i o n .Run (new F o r m l ());
}
}
}

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).

E xam p le 3.33. T w o-p layer m en u op tion .


// Menu event handler
private void TwoPlayer_Click(object sender, S y s t e m .EventArgs e) {
g a m eS ta te .currentMode = Ga m e S t a t e .M o d e .TwoPlayer;
S e t u p ();
}

E xam p le 3.34. S in g le-p la y e r m en u op tion .


// Menu event handler
private void SinglePlayer_Click(object sender, S y s t e m .EventArgs e) {
g a m e St at e.currentMode = Ga m e S t a t e .M o d e .SinglePlayer;
Setup ();
}

175
C# and Game Programming

E xam p le 3.35. D em o v e r sio n m en u op tion .


// Menu event handler
private void DemoVersion_Click(object sender, S ys t e m .EventArgs e) {
g a me St at e.currentMode = Ga me St ate.Mode.DemoMode;
S e t u p ();
}

E xam p le 3.36. S u b fu n c tio n c a lle d by th e m en u op tion .


public void Setup () {
// (Re) set member variables.
g am eS t a t e .currentState = G am e S t a t e .S t a t e .Started;
g am eS t a t e .currentSpeed = G am e S t a t e .SPEED_DEFAULT;

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 ();
}

Introduction to Artificial Intelligence


Artificial Intelligence (AI), in its simplest form, is essentially the modeling or sim ulation of
hum an responses th a t pertain to a certain situation or set of conditions. These responses
m ight be based on p a tte rn s or m athem atical equations such as tracking or evasion, but
the initial reactions are usually random base m ovements. A rtificially driven program s
m ust include both a realistic representation of hum an lim itation, like the ability to m ake
errors and/or the occasional lucky shot, b ut it m ust also represent an impersonal, consis­
ten t opponent in its ability to repeat the same level of skill over and over (at least until we
tire and shut it off). Of course, the AI we’ll discuss here is only a minor introduction to th a t

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).

E xam p le 3.37. T en n is AI le ft p layer.


// Left player artificial intelligence
public void Ten ni sA Ip la ye rL () {
// if ball active move left player
if(th eB al l.isActive == true) {
sw it ch(theBall.direction) {

177
C# and Game Programming

case 1: / / i f ball is moving SW move south to meet


if( th eB al l.imagePosY > p l a y e r L .imagePosY) {
p l a y e r L .direction = A n i ma te dl ma ge .SOUTH;
}
break;

case 4: / / i f ball is moving W playerL will line up to meet


case 8:
i f( the Ba ll .imagePosY < p l a y e r L .imagePosY) {
playerL.direction = Animatedlmage.NORTH; // move north
} else if(th eB al l.imagePosY > p l a y e r L .imagePosY) {
playerL.direction = Animatedlmage.SOUTH; // move south
}
break;

case 7: // if all is moving NW move north to meet


if(t he Ba ll .imagePosY < p l a y e r L .imagePosY) {
p l a y e r L .direction = A n i m at ed lm ag e.NORTH;
}

E xam p le 3.38. T en n is AI rig h t p layer.


// Right player artificial intelligence
public void TennisAIplayerR () {
// stops playerR from trying to hit the ball after it passes
i f (t h e B a l l .imagePosX > p l a y e r R .imagePosX+25){
return;

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

Paddle Tennis: Putting It All Together

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).

MEDIA_ROOT is an abbreviated reference used to find the location of our graphic


and sound files; . \media\ refers to a subfolder listed with each game. The
hardw ired version reads as @ " C : \ C # a n d G a m e P r o g r a m m i n g
DirectXEdition\Chapter3\Tennis.C#\ TennisDX9.C#\Media\";.

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).

Game 2 —Space Fighters


O ur second game, Space Fighters, although simple, does include several techniques th a t
you should find useful. We’ll begin by jotting down a quick list of thoughts, a.k.a. b ra in ­
storm ing, and we’ll take a few m om ents to develop our characters.

179
C# and Game Programming

Brainstorming

E xam p le 3.40. B r a in sto r m in g S p a ce F ig h ters.

1. The game should have two players th a t will appear as spaceships.


2. Again, one player will be placed on the right and the other on the
left. The game s ta rts the m om ent it’s loaded.
3. The players’ movements should be two-dim ensional w ith respect to
the screen, but they should also include diagonal movements.
4. The ships should have a th ru st, bu t not a brake or reverse,
allowing m om entum to carry them forward.
5. The two ships will have weapons, or at least one weapon, nam ely
a m issile th a t can be fired a t its opponent. B ut to keep things
sim ple, the m issiles won’t be able to injure th e ir own ship.
6. Again, we’ll set up a m enu option for one or two players, and
we’ll add in some AI for a one-player option.
7. We’ll use a black background w ith sta rs random ly placed across
it. The sta rs will be sm aller versions of our sun.
8. The ships should have contrasting colors—those colors will also
rep resen t th e color of th e ir weapons.
9. The ships should m ake sounds including a th ru st, w eapon’s fire,
and an explosion when hit.
10. The ships should not be able to fire w hen dead, nor should they
be able to get hit.
11. Set the game to end once a player gets, say, five kills. Also, if a
player is killed by crashing into the sun, he will lose a point.
12. Players will have to re s ta rt after they die.
13. We’ll include a comm and th a t allows players to revive th e ir
dam aged ships; these controls can double as hyperspace mode,
allowing active ships to random ly travel through unseen
dimensions, reappearing on some other portion of the screen
(including appearing inside the sun and/or on top of the other ship).

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.

Selecting Characters & Plotting Motions


O ur second step is to draw out some basic images, like spaceships, their exhaust trails, and
a large sun th a t will be conspicuously placed in the center of our screen. The ships will be
basically identical, but w ith contrasting colors, and the exhaust trail will be superimposed
onto those ships when their engines are active (see Screen Shots 3.17-3.19).

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 .

Moving Forward: (x, y) *


< ( 25, 5) < ( 35, 5)
* *
( 10, 10) ( 20, 10) < ( 22. 10) < ( 37, 10)
*
Rotating the crafts line of fire:
—i * .....-...— * ........ *
*► MA ► M* ► T
* *
___ .

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).

E xam p le 3.42. The S h ip ’s M om entum .

Ship's Momentum:
(10, 10) (15, 10) (20, 10)

*► M i
* * *

m i5> ▼ 0 * ij)

W riting the Algorithm


The comm ents listed here are supplem ental to the Paddle Tennis algorithm . Here, we’ll
expand the descriptions to include the details of these secondary subprogram s. Again,
these instructions are in reference to the older version of this program, but there are still
many sim ilarities between the two languages.

E xam p le 3.43. A lgorith m for S p ace F ig h ters.

1. Link our program to the previous game, using m enu.cpp,


gam es.cpp, etc.
2. Reference our m ain function screen size and access the proper
subprogram s.

183
C# and Game Programming

3. W rite a function to handle the unique turn in g m otions required


by this game (see Exam ple 3.37).
4. Include a function th a t p ain ts the sta rs and the screen black.
5. Again, we’ll w ant to access our variables as class m em bers listed
in an additional subprogram .
6. Set the variables/m em bers including paths.

Inside the while loop:


7. W rite a function th a t removes all residual im ages using a
combination of calls to blank characters and the pain t sta r
function.
8. Set the colors rem em bering to change the color for each vessel.
Each change in color will require its own declaration.
9. Display all characters.
10. We’ll still need to anim ate our weapon—this tim e we’ll use all
eight directions (see Exam ple 3.44).
11. O ur lim its will no longer stop the characters; in stead we’ll w rap
th eir m ovem ents around the screen. Projecting our characters to
the opposite side m eans th a t we won’t have to alte r th eir paths.
12. There are four sounds associated w ith this game—H it.w av (used
when a player dies), Fire.wav (used to represent weapons fire),
Gravity.wav (used to em phasis the pull of gravity), and
thrust.w av (used to represent the ship’s engine).
13. Collision detection (usually ends up in the destruction of a ship).
Activate the collision detection routine whenever a weapon is
active.
14. Set the w eapon’s movement. M ake it equal to the p a th each ship
is facing at the m om ent the weapons are fired. If the m issiles
reach the end of the screen, they’ll also be rerouted (traveling a
total of 100 cycles before term ination).
15. Add a force of m om entum th a t keeps the ship moving in one
direction even if the ship tu rn s.
16. Only display the characters w hen they’re active. If they’re not
active, display the exploding ship in th e ir place.
17. R epeat the loop un til either player scores five kills; either the
loop will term in ate on request or w hen th a t goal is reached.

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.

E xam p le 3.44. E ig h t d ir e c tio n s o f m ovem en t.

(90°)
(135°) 7 8 9 (45°)

(180°) 4 M ► 6 (0°= 360°)

(225°) 1 2 3 (315°)
(270°)

Setting up the Compiler


At this point, we need to get the compiler up and running; repeat the steps used to link the
class base and all of its counterparts. If you’d prefer to use c h a p te r 3 \ p r o j e c t 2, you can
just load it up, but if you’re building from scratch you’ll have to remember to add each file to
the project, and in some cases, you’ll have to rem em ber to load the Windows M ultim edia
Library. Again, we’ll need to build several user-defined functions with a final m ain function
th a t controls this game (refer to the previous sections as needed).

Animating Characters: Animating Spaceships


The key to anim ating the spaceship is keeping track of the direction the spaceship is
facing and then drawing the corresponding image for th a t direction. Since each player can
tu rn the spaceship, we need to update the direction of the spaceship (see Exam ple 3,45).
Now th a t we can keep track of the direction, we need a function th a t will display the
appropriate image for th a t direction (see Example 3.46). In Example 3.47, you can see how
this function is called for Player 1. The code is sim ilar for Player 2. Note th a t this function
m akes use of arrays which are covered in C hapter 4.

185
C# and Game Programming

Exam ple 3.45. Spaceship character d irection (A nim atedlm age.es).


// Rotate the direction by the specified amount
// increment is in 45 degree steps
virtual public void RotateDirection (int increment) {
int result = increment + direction;

if (result > 8) {
result %= 8;
if (result == 0)
result = 8;
} else if (result < 1) {
result = (result % 8) + 8;
}
direction = result;

E xam p le 3.46. D isp la y in g g r a p h ic s (P layerIm ageA rray.es).


// overridden member which displays the image with an index ==
// to the he adi ng a ssoc iat ed with the image,
override publ ic void Disp lay (Gr aph ics g) {
if (direction >= 0 && dire cti on <= a l m a g e s .G e t L e n g t h (0))
g .D r a w l m ag e ( a l m a g e s [ d i r e c t i o n ] , imagePosX, imagePosY,
imageWidth, i m a g e H e i g h t ) ;
}

E xam p le 3.47.Code to d raw P la y er l ’s S h ip an d E x h a u st


pla ye rl .Display(g);
if ( pl Ev ent .isActive) {
e x ha u s t l m a g e s [ p l a y e r 1.d i r e c t io n ] .i m a g eP o s X =
p l a y e r l .imagePosX;
e x ha u s t I m a g e s [ p l a y e r 1.d i r e c t io n ] .i m a g eP o s Y =
p l a y e r l .imagePosY;
e x h a u s t l m a g e s [ p l a y e r l .d i r e c t i o n ] .D i s p l a y ( g ) ;
}

As with a ship’s image, displaying the exhaust trail is simply a matter of


reading in the ship’s coordinates and displaying the appropriate image.

186
Chapter 3: Writing Games

Animating Characters: Projectiles and Explosions


As w ith th eir character counterparts, our projectiles m ust rely on a com bination of func­
tions and events including activation, anim ation, collision detection, and deactivation.
While most of these attrib u tes are integrated w ithin other functions we can still define a
projectile’s behavior based on a few lines of coding (see Example 3.48).

E xam p le 3.48. C o llisio n d e tec tio n .

public bool CheckShipCollision(Player player) {


Player opponent = (player == playerl) ? player2 : playerl;

// Collided with another ship?


if (player.Intersects(opponent)) {
// Successful ramming action!!
ShipCollided (opponent, player);
return true;
}

// Collided with the sun?


if (player.Intersects (theSun)) {
ShipCollided (player, n u l l ) ;
return true;
}

// 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

Adding Directlnput: The Keyboard and Joystick

A ship in space moves quite differently th a n a m an on a tennis court. Thus, it is logical to


assum e th a t our constructs for the keyboard and joystick would be quite different. It is
also im portant to note th a t Space F ighter does not require the use of a mouse; hence, no
mouse applications will be included. Space Fighter does require a th ru st and two angles of
movement, 45 degrees positive and 45 degrees negative, effectively tu rn in g the vessels
both left and right. Keeping in m ind th a t the two vessels begin in different position and
th a t our algorithm requires a generic solution, we conclude th a t an ab stract model of
rotation is required (see Example 3.49).

E xam p le 3.49. K eyb oard an d J o y s tic k co n tro ls.

private void K e yb oa rd _T ic k(object sender, S y s t e m .EventArgs e) {

keyboard = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);


k ey bo ar d.Prope rt ie s.BufferSize = 8;
ke yb oa rd .A c q u i r e ();

KeyboardState state = k e yb oa rd .GetCurrentKeyboardState();

for (Key k = Key.Escape; k <= K e y .M ed iaSelect; k++) {


if (state[k] && k == Key.W) {

private void Joystick_Tick(object sender, System.EventArgs e) {


foreach (Deviceinstance instance in
M a n a g e r .GetDevices(DeviceClass.GameControl,
En umDevicesFlags.At ta ch edOnly)) {
joystick = new Microsoft. DirectX. Direct Input. Device (instance. InstanceGuid) ;
break;
}

if (joystick == null) {
retu rn ;
}

188
Chapter 3: Writing Games

joyst ic k.SetDataFormat (DeviceDataFormat.Joystick);


foreach (DeviceObjectlnstance d in j o y st ic k.O b je ct s) {
if ((0 != (d.Objectld & (i n t )DeviceObjectTypeFlags.A x i s ))) {
j o y s t i c k .Proper ti es .SetRange (P ar am eterHow.ById,
d.Objectld, new I n p u tR an ge (-1000, 1000));

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 (-600 > State.Y) {


if (!p l a y e r 2 .isActive)
p l a y e r 2 .isActive = true;
p l a y e r 2 .Random iz eP os it io n();
}

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);

byte[] buttons = S t a t e .GetButtons ();


foreach (byte b in buttons) {
if (0 != (b & 0x80)) {
for (int i = 0; i < MAX_MISSILES; i++) {
if (player2Missiles[i].isActive == false) {
FireMissile (player2, p layer2Missiles);
break;

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.

E xam p le 3.50. S p ace F ig h ter gra p h ics.

// Draw the scores


b uf f e r .ColorFill(Color.Black) ;
b u f f e r .ForeColor = Color.Red;
b u f f e r .D r a w T e x t (4 * SCALE, 2 * SCALE, p l a y e r l .s c o r e .T o S t r i n g (), false);
b u f f e r .ForeColor = Color.Blue;
b u f f e r .DrawText (16 * SCALE, 2 * SCALE, p l a y e r 2 .s c o r e .ToString () , false);

// Draw player 1 & its appropriate exhaust


try {
destination = new Re ctangle(playerl.imagePosX, p l a y e r l .imagePosY,
SCALE, SCALE);
b u f f e r .Draw(destination, PlayerLDraw [playerl.direct io n],
D ra wF la gs .W a i t );
} catch (SurfaceLostException) {
CreateSurfaces ();

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).

E xam p le 3.51. R an d om ized p o sitio n (A n im a ted lm a g e.es).

// reposition the object in a random place within its constraintBox


public void R andomizePosition() {
Random rnd = new Random ();
imagePosX = r n d .Next(constraintBox.Width - imageWidth);
imagePosY = r n d .N ext(constraintBox.Height - imageHeight);
direction = rnd.Next (1, 8);
}

Boundaries & Projectile Limits


The next two key components are the ship’s boundaries and the lim its of the ships’ projec­
tiles. Since this game w asn’t based on a set field of screen lim its, our previous lim itations
should not apply. Instead, we’ll use those boundaries to indicate a chance to loop or reposi­
tion using x , y-zero to x, y-max as our coordinates. O ur players’ paths will not change, nor
will the ships’vectors (see Example 3.52).

E xam p le 3.52. L o o p in g th e sc r e e n b o u n d a r ie s (A n im a ted lm a g e.es).


virtual public bool W r a p I n B o x O {
bool retVal = false;

if (!isActive)
return false;

191
C# and Game Programming

if (imagePosX < constr ai nt Bo x.X) {


imagePosX = constrai nt Bo x.X + co n st raintBox.Width - imageWidth;
retVal = true;
} else if ((imagePosX + imageWidth) >
(constraintBox.X + c on straintBox.W i d t h ) ) {
imagePosX = constra in tB ox .X;
retVal = true;
}

if (imagePosY < constra in tB ox .Y) {


imagePosY = constrai nt Bo x.Y + constra in tB ox .Height -
imageHeight;
retVal = true;
} else if ((imagePosY + imageHeight) >
(constraintBox.Y + co nstraintBox.He ig ht )) {
imagePosY = constra in tB ox .Y;
retVal = true;

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).

E xam p le 3.53. I n itia tin g w ea p o n s.


// Fire a missile (if any available) from the given player
public void FireMissile(Player player, Animatedlmage [] missiles) {
if (!p l a y e r .isActive)
return;

for (int i = 0; i < MA X_ MISSILES; i++) {


// shoot the first missile that's not already out there!
if (!m i s s i l e s [i ].isActive) {
// set missiles properties so that it will get
// properly animated
m i s s i l e s [i ].isActive = true;
m i s s i l e s [i ].direction = p l a y e r .direction;
m i s s i l e s [i ].imagePosX = p l a y e r .imagePosX;

192
Chapter 3: Writing Games

missiles [i] .imagePosY = p l a y e r .imagePosY;

TimedEvent missileEvent = t i m e r .g e t E v e n t ("playerMissile" + i ) ;


m i s s i le Ev en t.R e s e t ();

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;

E xam p le 3.54. A n im a tin g w ea p o n s.

public void MoveMissile(TimedEvent e, Object o b j ) {


if (gameState.currentState == Ga me S t a t e .S t a t e .Stopped) {
e.isActive = false;
return;
}

Animatedlmage missile = (Animatedlmage) ob j ;


if (!m i s s i l e .isActive) {
e.isActive = false;
}

for (int i = 0; i < g a m e St at e.currentSpeed; i + +) {


missile.Animate ();
m i s s i l e .WrapInBox ();

CheckMissileCollision (missile);
}

if (e.tickCounter <= 1)
m i s s i l e .isActive = false;

193
C# and Game Programming

□rawing with DirectDraw

In Chapters 5, we take an extended look at the properties associated with the


Direct3D and GDI+ drawing tools. This section is meant to introduce a limited
set of DirectDraw methods used to create fonts, lines, curves, and shapes,
which will aid in creating rendered versions of our first set of games.

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

Exam ple 3.59. R ectangles and ellip ses display.

In addition to DrawBox, we can also create rectangles using the DrawFast


option. While DrawFast does not increase hardware draw time, it can increase
software draw time by approximately 10%. DrawFast is written using the x-
and y-coordinates, source surface, source rectangle, and a flag setting).

// 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);

Artificial Intelligence: Evasion


The previous section on artificial intelligence explained the basic concepts of tracking and
random motions, but we left out another concept commonly known as evasion. Evasion, in
coding term s, is simply the reverse of tracking. Here, ra th e r th a n moving closer to an
object, our opponent’s characters are told to avoid it, th u s creating the illusion of in telli­
gently driven tactics. We’ll need to include a fourth function th a t allows for weapons fire;
these functions are listed as Examples 3.61-3.64.

196
Chapter 3: Writing Games

Exam ple 3.61. AI m anaging subprogram.


public void SpaceFighterAI () {
if (!p l a y e r l .isActive) {
p l a y e r l .isActive = true;
p l a y e r l .RandomizeP os it io n();
}
Random rnd = new R a n d o m ();
int rndNum = r n d .Next (10);

if (rndNum < 5) // 50% of the time do nothing


return;

if (rndNum < 8) { // 80% of the time check for imminent crash


if (playerl.imagePosX < t h e S u n .imagePosX + 70 &&
p l a y e r l .imagePosX > t h e S u n .imagePosX - 70 &&
p l a y e r l .imagePosY > t h e S u n .imagePosY - 70 &&
p l a y e r l .imagePosY > t h e S u n .imagePosY - 70)
p l a y e r l .Randomiz eP os it io n ();
}

if (rndNum < 8) { // 20% (only if 6 & 7)


for (int i = 0; i < M AX _M ISSILES; i++) {
if (player2Missiles [i] .isActive) {
Evade(player2Missiles[i]);
plLastDirection = p l a y e r l .direction;
EngageThrusters(playerl);
return;

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

E xam ple 3.62. Tracking.


public void T r a c k () {
int tempDir = 0;

if (playerl.imagePosX > p l a y e r 2 .imagePosX &&


p l a y e r l .imagePosY > p l a y e r 2 .imagePosY)
tempDir = A n im at ed lm ag e.NORTHWEST;
else if (playerl.imagePosX > p l a y e r 2 .imagePosX &&
p l a y e r l .imagePosY < p l a y e r 2 .imagePosY)
tempDir = A n i m at ed lm ag e.SOUTHWEST;

Random rnd = new Random ();


if (rnd.Next (10) > 5) {
p l a y e r l .direction = tempDir;
playerl.Animate ();
}

E xam p le 3.63. E vasion .


public void Evade(Animatedlmage inbound) {
int tempDir = 0;

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 ();
}

E xam p le 3.64. AI m a n a g in g Tim er.


public void AlienAI_Timer_Click(object sender, S y st em .EventArgs e) {
if (g a m eS ta te .currentMode == Ga me S t a t e .M o d e .SinglePlayer)
Space Fi gh te rA I();
}

Including Obstacles: The Sun


A nother excellent way to increase the enjoym ent of a game is in the insertion of field
obstacles. The first obstacle we’ll create is a sm all sun in the middle of our screen, which
is like a little gravity well, slowly pulling in its prey u ntil Bang! The ships m ake contact
w ith its center. We’ll set up the force of gravity to pull once every 20 cycles, displacing
the ships w ith increasing increm ents (see Exam ples 3.65 and 3.66).

E xam p le 3.65. The sun.


// Initialize the sun
theSun = new S h a p e s (t h i s .Clie nt Si ze .W i d t h/ 2,t h i s .Clie nt Si ze .He ight/2) ;
t h e S u n .Rescalelmage (2 * SCALE, 2 * SCALE);
t h e S u n .isActive = true;
t h e S u n .imagePosX = t h i s .C l ie nt Si ze .W i d t h / 2 ;
t h e S u n .imagePosY = t h i s .C l i e nt Si ze .Heigh t/ 2;

newEvent = new TimedEvent(new TickHandler(Gravity));


n e w E v e n t .isActive = true;
timer.addEvent(newEvent, GRAVITY_SPEED, "" ) ;

19 9
C# and Game Programming

E xam p le 3.66. The su n ’s g r a v ita tio n a l pull.

public void ExertGravitationalPull(Player player) {


if (player.imagePosX != Cl ie nt S i z e .Width >> 1)
p l a y e r .imagePosX += (player.imagePosX >
(ClientSize.Width » 1)) ? -GRAVITY_EFFECT : GRAVITY_EFFECT;
if (player.imagePosY != Cl ie n t S i z e .Height >> 1)
p l a y e r .imagePosY += (player.imagePosY >
(ClientSize.Height » 1)) ? -GRAVITY EFFECT : GRAVITY_EFFECT;

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.

E xam p le 3.67. A d d in g m o m en tu m to th e gam e.


// Start up the player's thrusters
public void EngageThr us te rs (Player player) {
if (player.isActive) {
if (player == playerl)
p l E v e n t .Reset (); // reset the timer from now
else
p 2 E v e n t .Reset (); // reset the timer from now
try {
SoundBuffer = new SecondaryBuffer(MEDIA_ROOT + "Thrust.wav", sound);
Sound Bu ff er .P l a y (0, BufferPla yF l ag s.Default);
} catch {
U t i l s .PlaySound(MEDIA_ROOT + "Thrust.WAV");
}
}

200
Chapter 3: Writing Games

Including M ore Obstacles: Asteroids as Extra Credit


Here we will develop a secondary set of characters th a t can be used to increase the difficulty
of our second game; these characters will have a list of attributes th at allows for independent
interaction. The attributes should include character positioning, object animation, and p ar­
tial to full destruction with multiple strikes. The asteroids’bodies should be developed using
the ASCII code characters 219 (as a block) and 32 (as a blank). Combinations of these char­
acters, including varying sizes, are shown Example 3.68.

E xam p le 3.68. D e v e lo p in g an a stero id .

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).

E xam p le 3.69. A d d in g a ste r o id s to th e gam e.

// Initialize the asteroids


Random rnd = new R a n d o m ();
asteroids = new Shapes[MAX_ASTEROIDS];
for (int i = 0; i < M AX _ASTEROIDS; i + +) {
// Note, there are only 4 image positions so strange
// things happen when MAX_ASTEROIDS > 4

201
C# and Game Programming

asteroids[i] = new Shapes((i % 2 == 1) ? 3 * SCALE :


20 * SC ALE, (i < 2 ? 3 * SCALE : 12 * SCALE));
a s t e r o i d s [i ].direction = rnd.Next (1, 8);
if (a s t e r o i d s [i ].direction == 0) {
a s t e r o i d s [i ].direction = i; // default
}
a s t e r o i d s [i ].constraintBox = t h i s .ClientRectangle;
a s t e r o i d s [i ].Rescalelmage (2 * SCALE, 2 * SCALE);

newEvent = new TimedEvent(new TickHandler(MoveAsteroids));


ne w E v e n t .payload = a s t e r o i d s [i ];
ne w E v e n t .isActive = true;
t i m e r .addEvent(newEvent, ASTEROID_SPEED, "asteroid" + i);
}

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).

E xam ple 3.70. T w o-p layer op tion .


private void TwoPlayer_Click(object sender, S y s t e m .EventArgs e) {
g am eS t a t e .currentMode = Ga me S t a t e .M o d e .TwoPlayer;
S e t u p ();
}

E xam ple 3.71. S in g le-p la y e r op tion .


private void SinglePlayer_Click(object sender, S y s t e m .EventArgs e) {
ga me S t a t e .currentMode = Ga me S t a t e .M o d e .SinglePlayer;
S e t u p ();
} .

202
Chapter 3: Writing Games

Exam ple 3.72. A dding Asteroids.


private void UseAsteroids_Click(object sender, System.EventArgs e) {
t hi s. menultem5.Checked = !t hi s. menultem5.Checked;
useAsteroids = t h i s .m e n u l t e m 5 .Checked;

for (int i = 0; i < MA X_ ASTEROIDS; i + +) {


as t eroids[i].isActive = useAsteroids;
t i m e r .g e t E v e n t ("asteroid" + i).isActive = useAsteroids;

E xam p le 3.73. S etu p & I n itia liz a tio n


// (re) Sets positional data, scores, and other game data
public void S e t u p () {
g a m e St at e.currentState = G am e S t a t e .S t a t e .Started;
g a me St at e.currentSpeed = DEFAULT_SPEED;

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;

p l a y e r 2 .imagePosX = t h i s .C l i en tS iz e .Width - 2*SCALE;


p l a y e r 2 .imagePosY = t h i s .C l i en tS iz e .Heigh t/ 2;
p l a y e r 2 .score = 0;
p l a y e r 2 .isActive = true;
p l a y e r 2 .direction = Animatedlmage.WEST;

for (int i = 0; i < MAX_MI SS IL ES ; i++) {


playerlMissiles [i] .isActive = false;
p la ye r2Missiles[i].isActive = false;
}

for (int i = 0; i < MAX_ASTEROIDS; i++) {


a s t e r o i d s [i ].Re sc al e l m a g e (2 * SCALE, 2 * SCALE);
}

t i m e r .S t a r t ();
}

203
C# and Game Programming

Space Fighters: Putting It All Together


Again, a m anaging subprogram is necessary to weave these components into the game.
Here, I’ve ported the final product to the book’s CD-ROM. (Note th a t C hapter 3 includes
four versions of this game, e.g., Forms, GDI+, GDI+ w ith DirectX, and pure DirectX. See
Example 3.74/SpaceFighter on the CD-ROM for details.)

Game 3 —Asteroid M iner


We can also construct a th ird game th a t relies m ainly on w hat we’ve already developed.
Asteroid M iner includes the goal of destroying asteroids ra th e r th a n an enem y’s vessel.
Here we’ll also w ant to review the techniques used to create a rendered version of the game
(see Example 3.75).

E xam p le 3.75. B r a in sto r m in g A stero id M iner.

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).

E xam p le 3.76. D ra w P ie d isp la y .

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

E xam ple 3.77. D raw P ie coding.


if (player.isActive == true) {
g .D r a w P i e (P e n s .B l u e , p l a y e r .imagePosX, p l a y e r .imagePosY,
SCALE, SCALE, p l a y e r .st a r t A n g l e (), 50);
if (plEvent.isActive) {
p l a y e r .Exhuast(g, B r u s h e s .A q u a ) ;
}
}

The Vortex is an a lte rn a te version of the sun, e.g.:

xl = ImagePosX, y l = ImagePosY+10
x2 = X+10, y2 = Y+10

x3 = X-10, y2 = Y-10

x4= X +10,y4=X -10


, Ty. Vortex/Sun
x5 = X-10, y 5 = X+10
u ia g r a m a.a. m e v o rtex/^ u n .

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).

E xam p le 3.78. E x h a u st (S h a p es.cs).


// game specific - draws an ellipse as connected to a FillPie ship
public int Exhaust(Graphics g, Brush bExhaustColor) {
switch (t h i s .dire ct io n) {
case 1:
g .FillEllipse (bExhaustColor, t h i s .imagePosX+21,
t h i s .imagePosY-1, 5, 5);
break;

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

Exam ple 3.79. A steroids.

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 );

E xam p le 3.81. A ste ro id s (S h a p es.cs).


// complex shape - reusable as a single item
public void Asteroid(Graphics g, Brush bAsteroidColor) {
P o i n t [] PolyRoid = {
new Point( th is .imagePosX-this.imageWidth/5,
t h i s .imagePosY-2*this.imageHeight/5) ,
new P oi nt(this.im agePosX+this.imageWidth/5,
t h i s .imagePosY-2*this.imageHeight/5) ,
new Poi nt (t hi s.i magePosX+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 Poi nt( th is .imagePosX+2*this.imageWidth/5,
t h i s .imagePosY+this.imageHeight/5),
new P oi nt (t hi s.i magePosX+this.imageWidth/5,
t h i s .imagePosY+this.imageHeight/5),
new Poi nt (t hi s.imagePosX+this.imageWidth/5,

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),};

g .FillPolygon (bAsteroidColor, PolyRoid);


}

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).

E xam p le 3.81. M issile s.

E xam p le 3.82. M issile cod in g.


// Draw missiles
for (int i = 0; i < M AX _M ISSILES; i + +) {
if (playerMissiles [i ].isActive)
g .FillEllipse (B r u s h e s .B l u e , playerMissiles [i ].imagePosX,
playerMissiles [i ].imagePosY, 5, 5);
}

Asteroid Miner: Putting it All Together

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.

If however, you happen to be a skimmer, someone who is not already familiar


with C#, then I’d recommend that you stop, go back, and do the work that it
takes to get here. There's really no point in struggling through the problems of
DirectX if you haven't already mastered the safer, yet equally rich, coding
presented under GDI+. Remember, much of the gaming structures are identical,
so you might as well learn them under the simpler format.

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

E xam ple 3.83. The try -ca tch block.


try {
// code
} catch () {
// some more code
}

E xam p le 3.84. The ig n o re e x c e p tio n .


Microsoft.DirectX.DirectXException.IgnoreExceptions();

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.

Common Errors, Problems, and Pitfalls


1. If the gam es are compiling, but you get a runtim e error and/or
you only detect the default sound, your references are probably
not to the appropriate directory. For example, if you’ve copied the
gam es to your D : \ \ drive, th en the C : \ \ listings 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, but also referenced a t the
appropriate locations.
2. Check to m ake sure your files are listed with the appropriate
directory. For example, the gam es listed in the text are clearly
m arked as coming from the C : \ \ drive under the subfolder
Gam es.N et, while th e CD-ROM versions are m arked as
SourceCodeX.
3. Are you using Microsoft Visual C# version 7?
- If your answ er is yes, see Q uestion 2.
- If your answ er is no, try looking up any errors or w arnings
in your com piler’s help menu.
4. Can you get any of the anim ation te st program s to work?
- If your answ er is yes, see Q uestion 3.

211
C# and Game Programming

- If your answ er is no, chances are th e re ’s a h u m an error. Try


beginning w ith a sim ple program . M ake sure it runs, and th en
slowly add code.
5. Are you having problem s w ith the linker or the compiler?
- If you answ ered linker, your problem lies w ith eith er your
settings or your subprogram s.
- If you answ ered compiler, you are more th a n likely dealing
w ith one of th e th ree basic errors explained in the first two
chapters.
6. Did you forget to add a subprogram ?
7. Did you open two files and attem p t to compile? (Solution: Close
everything and s ta rt a new workspace w ith the proper *.CS file.)
8. If all the program s give you the sam e error, the problem m ay be
in your setup.
9. If you got the Paddle Tennis program to work (project 1), but are
having trouble w ith e ith e r Space F ighter (project2) or A steroid
M iner (project3), th en ju st try sta rtin g again and rebuilding
slowly. The only real differences betw een the two program s are
perceptual and will not affect the compiler or computer.
10. If you cannot get the gam e program s to ru n on your system , try
continuing w ith the chapters and atte m p t to recompile these files
after you’ve gained more experience.

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

4. Do not color your characters using the sam e colors as th eir


backgrounds.
5. M ake backups of any and all of the gam es you create. You won’t
w ant to lose your h a rd work.
6. W rite everything to be reusable; try to lim it the num ber of
variables used in the m ain function.

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

H I d his chapter addresses a concept th a t lets us combine variables into a collective or


| aggregated set, provided they share the same base data type and some common
purpose. The first portion of this chapter explains this concept—properly referred
to as an array—from both its singular and m ultidim ensional perspectives. The second
portion of this chapter introduces another powerful concept known as the pointer and
several other keywords and processing commands (includingpredefined array / string func­
tions and data stream manipulations). I’ve also included two gam esthat end this chapter,
which allow for the application of these techniques from the perspective of the game pro­
grammer. The game will be developed using our basic object-oriented model, including many
of the generically w ritten subroutines listed in the previous chapters. There are also several
traditional concepts interm ixed in this chapter including bubble sorting, array searches,
and calculations of mean, median, mode, and range. (Note: Chapter 5 also offers some inter­
mediate array and string examples th a t involve an extended knowledge of classes).

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.

E xam p le 4.1. Im p le m en tin g an array.


int numberO, numberl, number2, number3, number4;
// Is approximately equivalent to
int [] number = new int [5];
// n u m b e r [0], n u m b e r [1], n u m b e r [2], number [3], number [4].

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.

E xam p le 4.2. The co m p o n e n ts o f an array.

number[0] // is the first component (or the replacement for numberO),


Console.Write(numberO); // can be converted to Console.Write(number[0]);

number[l] // is the second component (or the replacement for numberl),


Console.Write(numberl); // can be converted to Console.Write(number[1]);

number[2] // is the third component (or the replacement for number2) ,


for (int index = 0; index < number2; index++) // ...
for (int index = 0; index < n u m b e r [2]; index+t)

number[3] // is the fourth component (or the replacement for number3) ,


if (number3 == 27) // may be rewritten as if (number [3] == 27)

number[4] // is the fifth component (or the replacement for number4) ,


while (number4) // . . . while (number[4])

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).

Declaring and Referencing Arrays


The declaration of an array doesn’t vary greatly from the declaration of either a standard or
a constant variable. They are generally w ritten using lowercase lettering, and all of the
rules of variable nam ing still apply. The one significant difference is in the insertion of the
square brackets (dem onstrated in the last example), which both define an array and
allow us to reference its components. The capacity of an array is determ ined by the size of
the value placed inside those initializing brackets. The formal name for this type of value
is the indexed variable, but it is also known as the subscripted variable, or less precisely,
as an element (i.e., an elem ent of an array). The num ber of indexed variables (total spaces
reserved) is called the declared size, or just the size, while the data type used to declare
th a t array is called the base type (see Examples 4.3 and 4.4).

E xam p le 4.3. C o n v ertin g from sin g u la r v a r ia b le s to an array—p art 1.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;

char studentO, studentl, student2, student3, student4;

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

Co ns ol e. Wr it eL in e("Enter student l's grade :");


input = C o n s o l e .R e a d L i n e ();
studentO = c h a r .P a r s e (input);
C o n s o l e .W r i t e L i n e ("Enter student 2 ’s grade :");
input = C o n s o l e .R e a d L i n e ();
studentl = c h a r .P a r s e (i nput);

C o n s o l e .W r i t e L i n e ("Enter student 3 ?s grade :");


input = C o n s o l e .R e a d L i n e ();
student2 = c h a r .P a r s e (in put);

C o n s o l e .W r i t e L i n e ("Enter student 4's grade :");


input = C o n s o l e .R e a d L i n e ();
student3 = c h a r .P a r s e (in put);

C o n s o l e .W r i t e L i n e ("Enter student 5's grade :");


input = C o n s o l e .R e a d L i n e ();
student4 = c h a r .Parse(input);

C o n s o l e .W r i t e L i n e ("\nYour input was {0}, {1}, {2}, {3) {4]


studentO, studentl, student2, student3, student4);

E xam p le 4.4. C o n v ertin g from m u ltip le v a r ia b le s to an array—p art 2.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;
char[] student = new c h a r [5];

for (int index = 0; index < 5; index++) {


C o n s o l e .W r i t e L i n e ("Enter student l's grade :");
input = C o n s o l e .R e a d L i n e ();
s t u d e n t [index] = c h a r .P a r s e (i n p u t ) ;
}

218
Chapter 4: Arrays, Pointers, and Strings

Console.WriteLine ("\nYour input was {0}, {1}, {2}, {3}, {4}",


s t u d e n t [0], s t u d e n t [1], s t u d e n t [2], s t u d e n t [3],
s t u d e n t [4]);

In addition to displaying the values as fragm ents, we can also display them as a
whole (see Exam ple 4.5).

E xam p le 4.5. C o n v ertin g from m u ltip le v a r ia b le s to an array—p art 3.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;
char [] students_grades = new c h a r [5];

for (int index = 0; index < 5; index++) {


C o n s o l e .W r i t e L i n e ("Enter student {0}'s grade:",
(index+1));
input = C o n s o l e .R e a d L i n e ();
stude nt s_g ra de s[index] = c h a r .Parse(input);

C o n s o l e .Write ("Your input was ");


for (int index = 0; index < students_grades.Length; index++)
C o n s o le .W ri te (students _g ra de s[index]);

C o n s o l e .WriteLine () ;

Using Variable Names as Indexed Variables:


You can also use variable names when declaring and referencing arrays of
undetermined sizes. The one catch here is that those arrays are then limited
by that declaration. This holds true even when the variable used to declare
that array’s range is not a constant (see the section on dynamic arrays). For a
simple example of a variable declaration, see Example 4.6.

219
C# and Game Programming

Exam ple 4.6. V ariable d eclaration for an array.

int total_students = 35;


// this is equivalent to s tu de nts_grades[35]
c h a r [] students_grades = new c h a r [total_students];

Assigning Values to Arrays


In addition to declaring arrays, we will need to assign values to them , which can be
done either after th e a rray is declared, or as a p a rt of the declaration. There are three
stan d ard form ats; all include a reference to the d ata type followed by the array symbol
[ ], and the a rra y ’s definition. In each case, we will include a host of values contained
w ithin an opening and closing set of curly braces, as shown in Exam ple 4.7.

E xam p le 4.7. A ssig n in g v a lu e s to arrays.

// 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

'h', 'i', 'j', 'k1, '1', 1m ’};

// 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 .

string Stringl = "Damn it boy, its three o'clock in the morning."


string String2 = "What the hell are you doing up so late? \n";
string String3 'I'm just doing my homework Dad.\n";
string String4 = "Oh, I know what you're doing, turn those games off and
go to bed! \n";
string String5 "That's it! I'm quitting school and joining a software
company! \n";
string String6 = "Oh no you're not mister! We didn't raise you to develop
software! \n";

221
C# and Game Programming

Passing Arrays to Functions


In addition to using arrays inside of user-defined functions, we can also pass their values
either as elements or in their entirety. The techniques for doing so are similar to passing
standard arguments, but a few minor changes should be noted. The first type we’ll look at are
the elements themselves, since they require the least amount of alteration (see Example 4.9).

E xam p le 4.9. P a ssin g th e e le m e n ts o f an array.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;
int[] childrens_ages = new int [20];

for (int counter = 0; counter < ch il drens_ages.Length;


counter++) {
C o n s o l e .W r i t e L i n e ("Enter student (0}'s age:",
(counter+1) ) ;
input = C o n s o l e .R e a d L i n e ();
childrens_ages [counter] = i n t .P a r s e (input);
A g e i s m (childrens_ages [counter]);

static void Ageism(int tester) {


if (tester > 6)
C o n s o l e .W r i t e L i n e ("Your child is to old.\n")

We can also pass arrays containing literal constants, such as ages [0], ages
[1], and ages [2], etc.

We can also reapply this program using a call-by-reference m arker as shown in


Example 4.10.

222
Chapter 4: Arrays, Pointers, and Strings

Exam ple 4.10. C alls-by-reference in arrays.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;
int[] childrens_ages = new int[20];

for (int counter = 0; counter < childrens_ages.Length;


counter++) {
Console.WriteLine("Enter student {0}’s age:",
(counter + 1));
input = Console.ReadLine();
childrens_ages[counter] = int.Parse(input);

Ageism(ref childrens_ages[counter]);

if (childrens_ages[counter] > 6)
Console.WriteLine("Your child is to old.\n");
}
}

static void Ageism (ref int tester) {


Console.WriteLine(tester); // we're all too old
tester += 7;

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

E xam p le 4.11. P a ssin g an e n tir e array.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;
const int array_size = 20;
int[] childrens_ages = new int[array_size];

for (int counter = 0; counter < array_size; counter++) {


Console.WriteLine("Enter student {0}'s age:",
(counter+1));
input = Console.ReadLine();
childrens_ages[counter] = int.Parse(input);
Ageism(childrens_ages, counter);

static void Ageism(int[] tester, int index) {


if (tester[index] > 6)
Console.WriteLine("Your child is to old.\n");
else
Console.WriteLine("Okay.\n") ;

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.

Although unnecessary, it is quite possible to pass an array’s declarative size


as a call-by-reference variable. This dangerous maneuver may lead to the
accidental alteration of that array’s size, thus causing a runtime error and
possibly a system crash.

The three most effective ways to prevent such an error are:


1) Using the array’s length when referring to the array’s size;
2) Declaring the array using a constant variable;

224
Chapter 4: Arrays, Pointers, and Strings

3) Using call-by-mechanism variables when passing the variable.

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).

E xam ple 4.12. M u ltid im e n sio n a l arrays.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;
char[,] students_grades = new char[5, 5] ;

for (int i = 0; i < 5; i++) {


Console.WriteLine("Enter student {0}'s grades "
+ "from first to last:", (i+1));
for (int j = 0; j < 5; j++) {
input = Console.ReadLine();
students_grades[i, j] = char.Parse(input) ;

Console.Write ("Your input was");


for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++)
Console.Write (" {0} ", students_grades[i, j]) ;
} '

225
C# and Game Programming

Console.WriteLinei

C# includes a localized reference when dealing with variables declared as part


of the for loop. Thus any secondary for loops using the same variable name
would also have to be redeclared. This differs from C++, which only asks for a
second declaration if the variable falls out of scope.

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.

a [0] [0] a[0][l] A[0] [2] a[0][3] a[0][4]


a[l][0] a [l][l] A[l][2] a[l][3] a[l][4]
a[2][0] a[2][l] A[2][2] a [2] [3] a[2][4]
a[3] [0] a[3][l] A[3][2] a[3][3] a [3] [4]
a [4] [0] a[4][l] A[4][2] a[4][3] a [4] [4]
a[5][0] a[5][l] A[5][2] a[5][3] a [5] [4]
a[6][0] a[6][l] A[6] [2] a [6] [3] a [6] [4]
a [7] [0] a[7][l] A[7] [2] a[7][3] a [7] [4]
a[8][0] a[8][l] A[8][2] a[8][3] a [8] [4]
a[9][0] a[9][l] A[9] [2] a [9] [3] a [9] [4]

W here, a[10] [0]-a[10] [4] are Null (\0)

E xam p le 4.13. A rray v a lu es.

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).

E xam p le 4.14. T w o -d im en sio n a l arrays.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string[,] names = new string[6, 5];

for (int i = 0; i < 6; i++) {


Console.WriteLine("Enter student's name "
+ "(all names must include 5 letters): ");
for (int j = 0; j < 5; j++) {
names[i, j] = Console.ReadLine();
}
}

file(names);
}

static void file(string[,] tester) {


for (int i = 0; i < 6; i++ ) {
for (int j = 0; j < 5; j++)
Console.WriteLine(tester[i, j]),

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).

E xam p le 4.15. G rap h in g c o o r d in a te s x , y, z.

E xam p le 4.16. G rap h in g c o o r d in a te s i, j 9 and k.

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.

E xam p le 4.17. T h re e -d im e n sio n a l array v a lu e s.

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

e ', 1 Ir ’m 1, 'u', 't' },


i \ 1d ', 1i ’f 'm' , 'e' , 1n 1 },
s 1, 'i', 'o' , 'n', ’a ’, 11 1 },

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

{ ' ! ', '\ n ', 'A' , 'B' , 'C', 'D'


{'E\ 'F' , 'G' , 'H', 'I', ’J' }
{ 'K', 'L' , 'M' , 'N' , 'O' , 'P' }
I rp 1
{ 'Q ' / 'R ' , 'S' , 'U', 'V' }

{
{ '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) ;
}

static void Di sp la y( ch ar [,, ] print) {


const short sets = 7, rows = 5, columns = 6;
for (int i = 0; i < sets; i++) {
for (int j = 0 ; j < rows; j++)
for (int k = 0; k < columns; k++)
Co ns ol e . W r i t e ("{0}\a", print [i, j, k ] );
}

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.

E xam p le 4.19. B u bble sort.


using System;

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};

BubbleSort (simple_array, array_size);


}

static void BubbleSort (int [] my_array, short size) {


int temp = 0;
C o n s o l e .W r i t e L i n e ("\nRandom numbers inputted in this ord er ") ;

for (int i = 0; i < size; i + +)


Console .WriteLine (11{0 } ", my_array [i ] ) ;
for (int i = 0; i < size; i++)
for (int j = 0; j < size-1; j++)
if (my_array[j] > m y _ a r r a y [j+1]) {
temp = my_array[j];

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 ]);

Console .WriteLine (11\nand in descending order") ;


for (int i = size-1; i > -1; i--)
C o n s o l e .WriteLine (" {0}", my_array[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.

E xam p le 4.20. L in ear sea rch ( fin d in g a n u m b er in an array).


using System;

namespace Chapter^ {
class Classl {
static void Main() {
string input;
const int array_size = 100;

232
Chapter 4: Arrays, Pointers, and Strings

i n t [] our_array = new int[array_size];


int number, total;

CreateArray(our_array, array_size);

C o n s o l e .W r i t e L i n e ("Enter a number between 1-100:");


input = C o n s o l e .R e a d L i n e ();
number = i n t .P a r s e (input);

total = Comparison (our_array, number, array_size);


C o n s o l e .W r i t e L i n e ("That number occurred {0} times", total);
}

// creates a random array with values between 1 and 100


static void CreateArray (int[j random_array, int size) {
, Random rnd = new R a n d o m ();

for (int index = 0; index < size; index++)


rando m_ arr ay [index] = (i n t )M a t h .Round (rnd.NextDouble () 'k
100)

// searches that array with a linear search


static int Comparison (int [] array, int input, int size) {
int count = 0;
for (int index = 0; index < size; index++)
if (array[index] == input) count++;
return count;
}
}
}

E xam p le 4.21. B u b b le so rt an d b in a ry se a rc h ( fin d in g a n u m b er in an


array).
using System;

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

bool found = false;

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);

BinarySearch(our_array, array_size, input, array_size - 1,


0, ref f ound);

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;
}
}

// This function creates a random array of numbers


// with values between 1 and 100
static void CreateArray (long[] random_array) {
Random rnd = new Random ();

for (int index = 0; index < random _a rr ay .Length; index++)


r a n d om _a rr ay [in dex] = (long)(r n d .NextDouble () * 100+1);
}

static void BubbleSort (long[] my_array) {


long temp = 0;
C o n s o l e .W r i t e L i n e ("\nRandom numbers inputted in this order");

for (int i = 0; i < m y _ a r r a y .Le ng t h ; i++) {


Console.WriteLine(my_array[i ]);}
// sort
for (int i = 0; i < m y _ a r r a y .Length; i++) {
for (int j = 0; j < m y _ a r r a y .L en gth-1; j++) {
if (my_array[j] > m y _ a r r a y [j+1]) {
temp = my_array[j];
my_array[j] = m y _ a r r a y [j+1];
m y _ a r r a y [j+1] = temp ;
}

234
Chapter 4: Arrays, Pointers, and Strings

}
}
C on so le .W ri te Li ne ("\nsorting..A n "
+ "\nln ascending or der");

for (int index = 0; index < my_array.Length; index++) {


Console.WriteLine(my_array[index]);
}

Co ns ol e. Wr it eL in e();
}

// this function searches and compares


// data using a binary search pattern.
static void B i n a r y S e a r c h (l o n g [] array, long size, long input,
long high, long low, ref bool found) {
if (input < array[(size / 2) - 1]) {
if (input == array[high - 1])
found = true;
else if (input < array[(high / 2) - 1 ] )
BinarySearch (array, size, input, high / 2, low,
ref found);
else if (high > low)
BinarySearch (array, size, input, (high - 1), low,
ref found) ;}
else if (input > array[(size / 2) - 1]) {
if (low < 0 && input == a rray[low])
found = true;
else if (input > array[((high + low) / 2) - 1] &&
(high - low) >= 2)
BinarySearch (array, size, input, high,
(high + low) / 2, ref found);
else if (low < high)
BinarySearch (array, size, input, high, (low + 1),
ref found) ;
}
}
}
}

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];).

E xam ple 4.22. D yn am ic arrays.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
string input;
int array_size;

C o n s o l e .Write ("How many students in the classroom? ");


input = C o n s o l e .R e a d L i n e ();
array_size = i n t .P a r s e (input);

236
Chapter 4: Arrays, Pointers, and Strings

char [] students_grades = new Char[array_size];

for (int index = 0; index < students_grades.Length; index++) {


Co n s o l e .W r i t e L i n e ("Enter the {0}'s student's grade:",
(index + 1));
input = C o n s o l e .R e a d L i n e ();
students_grades[index] = c h a r .P a r s e (input);
}

C o n s o l e .W r i t e ("The grades were ;");


for(int index = 0; index < students_grades.Length; index++)
Console.Write (" {0} ", s t ud en ts_grades[index]);

C o n s o l e .W r i t e L i n e ();

The foreach loop


The f o r e a c h loop is a specialized process th a t is used to skim or scan through an
a rra y ’s elem ents w ithout th e common drudgery usually associated w ith listing th a t
a rra y ’s com ponents. It is generally w ritten to include both the keywords f o r e a c h and
i n and for th e m ost p art, it physically resem bles the notation used w hen describing the
for-loop process. One key difference, however, is th a t the indexing or searching value is
not allowed to be altered; th is would include even subtle m anipulation, such as the
increm enting or decrem enting operators. The f o r e a c h process (as I’m sure m any of
you a re aw are) is actually a n add-in from th e language V isual Basic, th u s th ere is no
equivalent in native C++ (see Exam ple 4.23).

E xam p le 4.23. The f o r e a c h loop.


using System;

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

foreach (char find in integer) {


if (find == 1u 1)
Console.WriteLine ("I found {0}", find);

Enumerating Constant Integers


A nother lim ited version of a collective set of values is the integer data type known as the
enumerator. This constant integer type (as in signed and unsign ed short, i n t e ­
ger, and long values) is a basic aggregated type th a t promotes simple reference m anipu­
lations. It also allows for some unique references such as user-defined data structures and
lists of assignm ents to those declarations. In itial stru ctu res are declared using the key­
word enum w ith instances of those values declared and assigned as if they were class
references. If no values are assigned to these references, th en the initial point would be
zero, and each new component would autom atically increm ent by one. However, we can
also short step this process by beginning a t some arb itra ry point (such as 2000), or we
could individually declare each value (see Example 4.24).

E xam p le 4.24. E n u m e r a tin g in te g e r s.


using System;

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}

public enum Year {Year2 = 2002, Year3, LeapYear}

static void Main() {


string input;
int TheMonth, TheDay, TheYear;

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);

C o n s o l e .W ri te ("What day of the Month is it? ");


input = C o n s o l e .R e a d L i n e ();
TheDay = i n t .Parse (input);

Co ns ol e . W r i t e ("What year is it 2002, 2003... ");


input = Con so le .R ea dL in e();
TheYear = i n t .P a r s e (input);

if (TheMonth == (int)M o n t h s .Feb &&


TheDay == (i n t )D a y .Feb29 &&
TheYear == (int) Y e a r .Leap Ye ar )
C o n s o l e .W r i t e L i n e ("Happy Leap Year!");

if (TheMonth == (int)Months.Apr &&


TheDay == (int)Day.AprilFools)
C o n s o l e .W r i t e L i n e ("April F o o l 's " );

if (TheMonth == (int)Months.Sep &&


TheDay == (in t )D a y .Birthday)
C o n s o l e .W r i t e L i n e ("Happy B i r t h d a y !");

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).

ConsoteApplication2 • Microsoft Visual C *.N F T [design] - Class 1 .cs 1


&e &* tf" * Project ft* Debug loots Vtfndo* t£ ip

(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

<£] Navigate Backward CtrO-

TaskUst
Od-fShlt*- .................. ____________ 1.......
> vr line
I________Click here to add a new task___________________
' Program 'C^Documents and Settngs\Piague\My Do

?) Tasklist! (3 Output j & Search Results t o r imafe

_33 12 Col 46 Ch 46 JNS

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

He &* tfew 5»o)ect QJd feebug loo k jjflndow

S %9b. >• «*=• I ! | ♦ **** .

^ ° ' r*- m
Setting Visual€# ProjectProperties Classl.cs J SoMon Explww - ConsoleAppl.

^CoosoteAppteatton2, .Classl ~ j5 Ja%Main(strini]args) ®m\K


C on sole.H riteL in e{"U S h ort - " + s i t e o f ( u s h o r t ) ) ; & Solution'

C on sole.W riteL in e ("S h ort - " + s i t e o f ( s h o r t ) ) ; a-IP!


j] References
C on sole.W riteL in e("U In t » * + s i t e o f ( u i n t ) ) ;
C o n s o le .W r ite L in e ("I n t • » + s i t e o f ( i n t ) ) ;
^ Ass4wnbJyInfo.es Screen
g dassl.es
Console.WriteLine("Ulong « n + siteof(ulong));
Console. WriteLine ("Lon® • m + siteof (longr)); Shot
Console.WriteLine("Float * " + siteof(float));
Console.WriteLine("Double - " + siteof(double)); 4.2.
Console.WriteLine("Decimal » n + siteof(decimal));
)))

Now go to th e listing labeled “Configuration P roperties.” Select “Build” from th a t


sublist and click on the “False” value u nder the “Allow unsafe code blocks.” From there,
an arrow will a p p ear—use it to select the “True” setting and press “Apply” (see Screen
Shot 4.3).

CousoteApplkalkm ? • Microsoft Visual£$*H£T j^desigp] Classl .«*


EM E* frojecl &u#d Qebug look SM o« tK*>

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*

Allow unsafe code blocks


Enable use of the unsafe keyword (/unsafe).

G3 Tasklist 1 El OutpUs frmsafeT

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

Console.WriteLine (" {0 } {1}", vari ab le l, *pointerl)


Console.WriteLine (" {0 } {1}", v ar iable2, *pointer2)
Console.WriteLine (” {0 } {1}", v ar iable3, *pointer3)
Console.WriteLine (" {o } {1}", vari ab le 4, *pointer4)

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.

“I just got this new pointer VISA—it has my name on it,


but the charges are linked to someone else’s account.”
“Are you sure th a t’s legal?”
“Well, not always, I have to use it in unsafe counties.”

Pointers can also assign locations to other pointers—see the code in Example 4.26.

E xam p le 4.26. A ssig n in g v a lu e s and m em ory lo c a tio n s to p o in ters.


using System;

namespace Chapter4 {
class Classl {
static unsafe void Main() {
int* pointerl, pointer2;
// Warning, pointer3 is not an actual pointer!
int variablel = 1, pointer3;

// Assigning a pointer to a value


pointerl = Svariablel;
// Pointer to pointer assignments DO NOT require the asterisk.
pointer2 = pointerl;
// Pointers can also pass values to variables.
pointer3 = *pointer2;

243
C# and Game Programming

Consol e. Wr it eL in e("{0} {1} {2} {3}M,


variablel, *pointerl, *pointer2, poi nt er 3) ;

*pointerl = 20; // the value inside that address is now 20.

Console.WriteLine ("{0} {1} {2} {3}",


variablel, *pointerl, *pointer2, po in te r3 );

The Keyword null:


The keyword null is the only value that can be assigned to an unassigned
pointer without causing an error. The null statement is also useful when passing
meaningless values to a generalized function as in MyFunction (SomeNumber,
null); where a second value is not required when the first value represents a
short-circuit event. The null value works in basically the same manner as did
the NULL value in C++, except now it’s actually a keyword.

Call-By-Reference Values with Pointer Arguments


As you’ll rem em ber from C hapter 2, we were able to w rite function calls as both calls-by-
value and calls-by-reference, bu t calls-by-reference also let us change the values of the
original variables. You should also recall (from our introduction to pointers) th a t calls-by-
reference are actually lim ited forms of pointers. This m akes it possible to rew rite those
program s so th a t they use actual pointer notation w ithout significantly changing those
program s (see Example 4.27)

E xam p le 4.27. C alls-b y-referen ce w ith p o in ter a rg u m en ts.


using System;

namespace Chapter4 {
class Classl {
static unsafe void Main() {
string input;
char race = 1Y 1;

244
Chapter 4: Arrays, Pointers, and Strings

int winner, number1 = 0, number2 = 0, number3 = 0;

Conso le .W ri te Li ne (" L e t 1s have a horse race.\n"


+ "To play select one of the horses below");

while (char.ToUpper (race) != *Nf) {


C o n s o l e .WriteLine ("(1) for Whitefire\n"
+ "(2) for The Train and, \n"
+ "(3) for Noisy Glue");

input = C o n s o l e .R e a d L i n e ();

t h e _ r a c e (&numberl, &number2, &number3);


t ie _ b r e a k e r (&numberl, &number2);
tie_breaker(&number2, &number3);
t ie _ b r e a k e r (&numberl, &number3);

winner = t h e _ w i n n e r (&numberl, &number2, &number3);


C o n s o l e .W r i t e ("And the winner is ");

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 ") ;

C o n s o l e .W r i t e ("Would you like to play again (Y/N)?");


input = C o n s o l e .R e a d L i n e ();
race = c h a r .Parse(input);

static unsafe void the_race(int *numberl, int *number2,


int *number3) {
Random rnd = new R a n d o m ();

*numberl = (int) (r n d .NextDouble ()* 100);


*number2 = (int) (r n d .NextDouble ()* 100);
*number3 = (int) (r n d .NextDouble ()* 100);
C o n s o l e .W r i t e (".");
}

static unsafe void t ie _ b r e a k e r (int *numl, int *num2) {


if (*numl == *num2)

245
C# and Game Programming

*num2 = *num2 - 1;
C o n s o l e .Write (" .");

static unsafe char t he _ w i n n e r (int *numl, int *num2, int *num3) {


char winner;
if (*numl > *num2 && *numl > *num3)
winner = 11 1;
else if (*num2 > *numl && *num2 > *num3)
winner = 12 1;
else winner = 13';
Console .Write (11." ) ;

return(winner);

Pointer Arithm etic


Pointer arithm etic is simply variable arithm etic as applied to pointers (note: asterisks are
required). In pointer arithmetic, pointers are used like variables to add, subtract, multiply,
divide, and find the rem ainder of stored values. Pointers can also be used with shorthand
notation and the incrementing and decrementing operators (incrementing & decrementing
operators also require the insertion of parentheses—see Examples 4.28 and 4.29).

E xam p le 4.28. A r ith m e tic w ith p o in ters.


using System;

namespace Chapter4 {
class Classl {
static unsafe void Main() {
int numberl = 0, number2 = 0;
int* pointerl = &number2;

numberl = numberl + 10; // Addition


*pointerl = *pointerl + 10;
Console.WriteLine ("{0} {1}"/ numberl, num be r2 );

numberl = numberl - 1; // Subtraction

246
Chapter 4: Arrays, Pointers, and Strings

*pointerl = *pointerl - 1;
C o n s o l e .WriteLine ("{0} {1}”, numberl, nu mber2);

numberl = numberl*2; // Multiplication


*pointerl = *pointerl*2;
C o n s o l e .WriteLine ("{0} {1}"/ numberl, number2);

numberl = numberl/2; // Division


*pointerl = *pointerl/2;
C o n s o l e .WriteLine ("{0} {1}", numberl, number2);

numberl = numberl%3; // Remainders


*pointerl = *pointerl%3;
C o n s o l e .WriteLine ("{0} {I}", numberl, number2);

E xam p le 4.29. S h o rth a n d n o ta tio n and th e in c r e m e n tin g and d e c r e m e n tin g


op erators.
using System;

namespace Chapter4 {
class Classl {
static unsafe void Main() {
int numberl = 0, number2 = 0;
int* pointerl = &number2;

for (int index = 0; index < 10; index++) {


numberl = number1++;
*pointerl = (*pointerl) ++ ;
}
C o n s o l e .WriteLine (” {0} {1}", numberl, number2);
numberl = numberl - 1;
*pointerl = (^pointer1)--;
C o n s o l e .WriteLine ("{0} {1}", numberl, number2);

// numberl = numberl + numberl


numberl = numberl += numberl;
// *pointerl = *pointerl + *pointerl
*pointerl = *pointerl += *pointerl;

247
C# and Game Programming

C o n s o l e .WriteLine (” {0} {1}", numberl, number 2) ;


// numberl = numberl - numberl
numberl = numberl -= numberl;
// *pointerl = *pointerl - *pointerl
*pointerl = *pointerl -= *pointerl;
C o n s o l e .WriteLine ("{0} {1}", numberl, n um be r2 );

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) ;

String and Address Arithm etic


S tring arithm etic is also fairly simple, but it doesn’t involve changing num eric values.
Instead, we’ll use arithm etic comm ands to move an a rra y ’s index from address to ad ­
dress. This is possible because of the strings sequentially stored memory locations. Since
we cannot know the spatial difference betw een any two strings, this type of memory
m anipulation m ust be lim ited to arrogated variables th a t are p a rt of the same string (see
memory m apping for further details).

248
Chapter 4: Arrays, Pointers, and Strings

Exam ple 4.30. M apping Memory.


Com puters allocate a certain am ount of Random Access Memory (RAM)
to each variable declared inside of a program . This mem ory is actually
p a rt of a com puter’s h ardw are, and is reused and/or overw ritten every
tim e we ru n a new program . The m ethods used to store v ariables and
th e exact locations in m em ory of those variables are irrelev an t to us as
program m ers, and will be left to books rela te d to com puter operating
system s and hard w are. O ur u n d e rsta n d in g of how and w here d a ta is
placed will have to be on an a b stra c t scale. This therefore includes an
im aginary point of reference th a t we can build upon to access and a lte r
any a rra y s or strin g s of d a ta declared in our program s.

F irst off, let’s assum e th a t we’ve ju st declared and initialized a character


a rra y or strin g to the values A, B, C, D, and E. We know th a t the
strin g s’positions will reflect our points (as in zero equals A, one equals
B and two equals C, etc.), bu t we don’t know how th is will relate to the
com puter’s placem ent of th a t d ata. If we th en reason th a t the com puter
places th e first com ponent A in some a rb itra ry location (say m em ory
location 1000), using th e basic form of 1 byte per character, we can
deduce th a t th e location 1001 would hold the value B, location 1002
would hold C, and so on. From this, we can also graph a m ap of the
locations:

M emory Location Referencing A rray Value in


Memory
[1000] a rra y [0] A
[1001 ] a rra y [1] B
[1002] array[2] C
[1003] array[3] D
[1004] array[4] E
[1005] array[5] \0

249
C# and Game Programming

If a character takes up 2 bytes per elem ent, th eir memory locations


would be listed as

Memory Location Referencing A rray Value in


Memory
[1000 - 1001] = array[0] = 1
[1002 - 1003] = arra y [l] = 2
[1004 - 1005] = a rra y [2] = 3
[1006 - 1007] = a rra y [3] = 4
[1008 - 1009] = array[4] = 5

In addition, if a d ata type takes up 4 bytes per elem ent, it would produce
a larger span or cluster of data.

M emory Location Referencing A rray Value in


Memory
[1000 - 1003] = array[0] = 1
[1004 - 1007] =: arra y [l] = 2
[1 0 0 8 - 1011] = array[2] = 3
[1 0 1 2 -1 0 1 5 ] = array[3] = 4
[1 0 1 6 -1 0 1 9 ] = array[4] = 5

Further, th is could continue on and on at least up to 64 bits (the 128-bit


m achines are not q u ite ready yet). D a ta th a t ta k e s up 8 bytes is
equivalent to:

M emory Location Referencing A rray Value in


Memory
[1000 - 1007] = array[0] = 1
[1 0 0 8 -1 0 1 5 ] = arra y [l] = 2
[1 0 1 6 - 1023] = array[2] = 3
[1 0 2 4 - 1031] = array[3] = 4
[1032 - 1039] = array[4] = 5

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.

E xam p le 4.31. S tr in g a r ith m e tic.


using System;

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);
}

static char M y T o u p p e r (char input) {


string alpha =
"abcdefghij klmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

for (int index = 0; index < 26; index++)


if (input == (alpha[index]))
input = (alpha[index + 26]);

251
C# and Game Programming

return (input);
}

static char MyTolower(char input) {


string alpha =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

for (int index = 26; index < 52; index++)


if (input == (alpha[index]))
input = (alpha[index - 26]);
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).

E xam p le 4.32. The v o id p o in ter.


using System;

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

MyFunction (&va riablel, 's’); // for short


MyFunction (&variable2, 1i ') // for integer
MyFunction (&variable3, 11') // for long
MyFunction (&variable4, 1f 1) // for float
MyFunction (&variable5,'d'); // for double
MyFunction (&variable6, 1e 1) // for decimal

Console.WriteLine ("{0}\n {1}\n {2}\n {3}\n {4}\n {5}\n",


variablel, variable2, variable3, variable4, variable5,
variable6)/

static unsafe void MyFunction (void ^values, char data_type) {


switch (data_type) {
case 's': {
* ( (short *)values) += 1;
break;
}

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;
}

Finding the Mean, Median, Mode, and Range


Another im portant exercise th a t we can illustrate with pointers and/or arrays is to use them
to find the mean, median, mode, and range of data. These can be very im portant tasks when
the need arises, but for now let’s ju st look at them as exercises we can do to improve our
skills. All four tasks will be wrapped into one large program, and the coding will be left for
you to go through as needed (see Example 4.33). Note: multiple modes mean th at there was
a tie when calculating the most frequently referenced variable.

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];

for (int i = 0; i < aSize; i++)


r a n d om_ ar ra y[i ] = (short) (r n d .NextDouble () * 100);

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);
}

// The mean is the average of the sum of the


// values placed inside the array,
static void M e a n ( s h o r t [] array) {

254
Chapter 4: Arrays, Pointers, and Strings

short average = 0, array_sum = 0;


for (int index = 0; index < a r r a y .Length; index++)
array_sum += a r r a y [index];

average = (short)(array_sum/array.L en gth);


Conso le .W ri te Li ne ("\nThe mean is " + a ve rage);

// 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 ) ;
}

// The mode is the most frequent number in the list.


// Note: If there's a tie multiple modes will appear
static void M o d e ( s h o r t [] array) {
s h o r t [] counter = new s h o r t [25], temp = new s h o r t [25];

for (int index = 0; index < a r r a y .Le ng th ; index++) {


for (int index2 = 0; index2 < a r r a y .Length; index2++) {
if (array[index] == a r r a y [i ndex2])
c o u n t e r [in dex] += 1;

for (int index = 0; index < a r r a y .Length; index++)


temp[index] = c o u n t e r [index];

Array.Sort(array);

for (int index = 0; index < a r r a y .Length; index++) {


if (counter[index] == temp [a rr ay .Le ngth-1]) {
if (index != 0 && array[index] != a r r a y [index-1]
C o n s o l e .W r i t e L i n e ("The mode is {0}",
a r r a y [index]);

255
C# and Game Programming

// Range- the difference between the


// highest number and the lowest number,
static void Range (short [] array) {
C o n s o l e .W r i t e L i n e ("The range spans from {0} to {1}",
a r r a y [0], a rr ay [a rr ay .Lengt h- 1]);
}

static void Display (short [] my_array) {


C o n s o l e .W r i t e L i n e ("\nRandom numbers inputted in this "
+ "order\n");
for (int i = 0; i < m y _ a r r a y .Length; i + +)
Console.WriteLine(my_array[i ]);

A r r a y .Sort(my_array);

Console.WriteLine("\nsorting...\n"
+ "\nln ascending order\n");

for (int i = 0; i < m y _ a r r a y .Length; i + +)


C o n s o l e .WriteLine (" {0}", m y _ a r r a y [i ]);

Console .WriteLine (11\nand in descending order\nfl);

A r r a y .Reverse(my_array);

for (int i = 0; i < m y _ a r r a y .Length; i++)


C o n s o l e .WriteLine (" {0}", my_array[i]) ;

Pointers as Arrays: The Keyword stackalloc


We can m anipulate pointers to include a basic value type a rray (this is equivalent to the
stan d ard C++ stackable array). To do so, we’ll also have to call on the stack allocating
command, stackalloc. Stack allocated arrays are lim ited to only one dim ension and
are generally w ritten with the pointer reference replacing reference of the a rray ’s square
brackets: for example, int* our_pointer = stackalloc int [array_size] ;
(see Example 4.34).

256
Chapter 4: Arrays, Pointers, and Strings

Exam ple 4.34. P ointers as arrays.


using System;

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];

for (int counter = 0; counter < array_size; counter++) {


C o n s o l e .WriteLine ("Enter student {0}'s age",
(counter+1));
kids[counter] = i n t .Parse(Console.R e a d L i n e ());
our_pointer[counter] = kids[counter];
}

Ageism (our_pointer, array_size);


}

static unsafe void Ageism (int* tester, int size) {


for (int counter = 0; counter < size; counter++) {
if ((int)* (tester + counter) > 6)
Console .W ri te Li ne ("Your child is to old.");
else
Console .W ri te Li ne ("{0}'s age is Okay", (counter+1)

257
C# and Game Programming

Double Asterisk Pointers


In addition to being able to pass pointer values to other pointers, you can also set up special
double asterisk pointers (pointers to pointers). These secondary pointers are as versatile as
regular pointers, except th a t they require some additional notation (see Examples 4.35 and
4.36).

E xam p le 4.35. P o in ter s to p o in ters.


using System;

namespace Chapter4 {
class Classl {
static unsafe void Main() {
int* pointerl, pointer2;
int** p ointer3;
int variablel = 1;

pointerl = &variablel; // variable to pointer


pointer2 = pointerl; // pointer to pointer
pointer3 = &pointerl; // pointer to double-pointer.

Console .WriteLine (11{0 }\n {1} \n {2 }\n {3}\nM,


variablel, *pointerl, *pointer2, **pointer3);

**pointer3 = 20; // the value inside that variablel is now 20.

C o n s o l e .WriteLine ("{0}\n {1}\n {2}\n {3}\n",


variablel, *pointerl, *pointer2, **pointer3);

Pointers can normally be assigned to other pointers without this special notation
(as in pointerl = pointer2 ;).
Chapter 4: Arrays, Pointers, and Strings

Exam ple 4.36. P assin g double asterisk pointers.


using System;

namespace Chapter4 {
class Classl {
static unsafe void Main() {
int variablel = 1;
int* pointerl = &variablel, pointer2 = pointerl;
int** pointer3 = &pointerl;

C o n s o l e .WriteLine ("{0}\n {1}\n {2}\n (3}\n",


variablel, *pointerl, *pointer2, **pointer3);

**pointer3 = pointers (**pointer3);

C o n s o l e .WriteLine ("{0}\n {1}\n {2}\n {3}\nM,


variablel, *pointerl, *pointer2, **pointer3) ;
}

static int pointers (int local_number) {


return (local_number = local_number + 20);
}

Functions Returning Pointers


The stan d ard nonvoid, user-defined function typically retu rn s a value th a t is a variable
of one of the four basic data types. This value is th en reassigned to a m atching/receiving
variable and the program continues. This procedure is only slightly altered when dealing
w ith functions th a t retu rn pointers. The key changes are based on the retu rn in g and
receiving values, which are both converted into pointers. We’ll also need to alter the nota­
tion w hen declaring those functions, but this is done by simply attaching an asterisk to
the function’s name. Be careful not to confuse this notation w ith the one used to declare a
pointer function (see Example 4.37).

259
C# and Game Programming

Exam ple 4.37. R eturning fu n ction s as pointers.


using System;

namespace Chapter^ {
class Classl {
static unsafe void Main() {
int variable;
int* pointer = &variable;

C o n s o l e .W r i t e L i n e ("Enter a number: " ) ;


variable = i n t .Parse(Console.R e a d L i n e ());
pointer = functionl(variable, p o in te r) ;

Conso le .W ri te Li ne ("\ n {0}", va ri able);


pointer = f u n c t i o n 2 (&variable, *pointer);

C o n s o l e .W r i t e L i n e ("\n {0}", variable);


Console .WriteLine (11\n {0}", function3 (pointer));
}

// These first two functions return pointers,


static unsafe int *functionl (int variable, int ^pointer) {
^pointer = v a r i a b l e * (*pointer);
return (pointer);
}

// This function returns a variable.


static unsafe int *function2 (int *pointer, int variable) {
*pointer = variable/ (*pointer);
return (pointer);
}

static unsafe int fu n c t i o n 3 (int *point) {


return (*point = 20);
}

Storage Class Specifiers: e x t e r n and s t a t i c


C# offers two storage class specifiers—e x te r n and s t a t i c . The first storage class specifier,
e x te rn, which is short for the word external, is prim arily used to transcend the lim itations

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:

A slightly less obvious choice would be to include th a t string as an array of characters,


i.e., “This is a string of data.” Of course, we’ve already seen th a t either of these cases can
be used as output (Console.Write (Stringl); and Console.Write (A rrayl [index]);). However,
it m ight not be as obvious to th in k of modifying these processes to include the passing of
argum ents and/or the ability to store data.
A literal collection of characters, or a string, can be passed to a function using the
sam e process as a stan d ard array. This string argum ent requires a defined param eter
(formally referred to as a string param eter), which is equivalent to an arra y ’s param eter.
The string will be listed in quotations, e.g., MyS tring ("This is a string of
d a t a " ) . The literal string will be stored as a string value: static void MyString
(string Stringl) {/* our string function * /} . In addition, since strings
handle literal constants differently th a n arrays, we will not suffer the effects of au to ­
m atic truncation when attem pting to add characters th a t include whitespaces. This
should also rem ind us of the getline function used in C++, as in c i n .getline (ar­
ray, array size) , w herein we were able to avoid such truncations.

261
C# and Game Programming

Manipulating String Data


A nother significant aspect of m anipulating string data comes from the use of the string
extensions. These are m ethods included in the Base Class Library th a t m ake m any of
the older string m anipulations obsolete. A few of the basic references include commands
th a t test, alter, and apply to both strings and th eir literal counterparts. The use of these
string m anipulators has found its way through both C (“string.h”) and C++ (“cstring”),
w ith these newly defined m ethods giving the clearest representation yet (see Table 4.1).

T able 4.1. M a n ip u la tin g str in g d ata in C#, C++, and C.


1 C++ ................. _ 1 C/C++
Cooies the value of our original string to a new string
using System; #inel ude <iostream> #inelude <iostream>
na me space C hapter4 # include <string> #include <cstring>
{class Classl using namespace std; using namespace std;
{static void MainQ 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",
SI, S2; string\n"), SI, S2; ♦SI;
51 = S; SI =S; SI =
52 = stnng.Copy(S); S2.assign(S); (ehar*)malloc(strlen(S)+1);
Console.WriteLine("{0}\n{ 1}", std::cout« SI « strcpy(Sl, S);
SI, S2); } } } std::endl std::cout« SI; }
« S2 « std::endl; }
Copies a limited portion ofa longer string to a shorter string
using System; #i nc 1ude <iostream> #include <iostream>
na mespace Chapter4 in c lu d e <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'\ SI; {string S("This is a {char S[ ] = "This is a string of
SI = S.Substring(0, 4); string\n"), SI; data\n", Sl[ ] = " M;
Console.WriteLine(”{0}”, SI); } } } Sl.assign(S, 0,4); stmcpy(Sl, S, 3);
std::cout« SI « std::cout« SI « std::endl;}
std::endl;}
Appends the original string with the additional string
using System; #include <iostream> #ificlude <iostream>
namespace Chapter4 #mclude <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 {char S[50] = "This is a string
Extra = "Good bye"; S("This is a string\n"), of data\n",
S = S.Insert(17, Extra); Extra("Good Bye\n"); Extra[] = "Good Bye\n";
Console.WriteLine("{0}", S); } } } S.append(Extra); strcat(S, Extra);

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

Extra = ’T h is is good bye”; string S("This is a S l[ ] = "This is a string\n",


if(Extra,Substring(0, string\n"), S2[ ] = "This is a string o f
4).Com pareTo(S.Substring(0,4)) = = S l ( ”This is a string\n"), data\n";
0) S2("Is this string larger? il(strcm p(Sl, S2) < 0)
Console.W riteLine(”They match!”); \n”); std::cout« "Super array is
else T = Sl.com pare(0, better \n";
Console. WriteLine( S l.siz e (), S 2 ,0, it(strncm p(Sl, Super Array, 4)
’’They don’t match!"); } } } S2.size()); = = 0)
if(T > 0) std::cout« "Are first 4 letter
c o u t« "S2 is greater" are equal \n"; }
« endl; }
Where 0 to SLsize()
equals the length o f SI,
and 0 to S2 equals the
length o f the
comparison.
Determines the length o f a string
using System; #inc!ude <iostream> #include <iostream>
namespace Chapter4 #inciude <string> #include <cstring>
{class C lassl using namespace std; using namespace std;
{static void Main() void main(void) void main(void)
{string S = "This is a string\n”; {string Stringl; {const int array_size = 100;
int ArrayLength = S.Length; std::cout« "Enter a Int length;
Console.W riteLine(S.Length); test sentence. \n"; char Array[array_size];
} } } std::getline(cin, std ::c o u t«
Stringl); "Enter a test sentence. \n";
int Length = std::cin.getline( Array,

There are dozens more, all quickly accessible from the visual compiler’s pop-up
\ menu.

Converting and Safeguarding Data


In addition to inputting and m anipulating data, we can also convert and safeguard against
data input errors. For example, when our users need to input num eric data, we can use
the broader string data type and then test and convert th a t data as necessary. The d ata
comparison functions are quite num erous, as shown in Table 4.2.

264
Chapter 4: Arrays, Pointers, and Strings

Commands/ Examples: Description:


char.lsLetterOrDigit Returns true when an alphanumeric character (A-Z,
a-z, or 0-9) is found.
char.IsLetter Returns true when an alphabetic character (A -Z or
a-z) is found.
char.IsSymbol Returns true when a character is found to be a
symbol.
char.IsControl Returns true when a control character (OxOO-OxlF
or 0x7F) is found
char.IsSeparator Returns true when a separator character is found
char.IsSurrogate Returns true when a surrogate character is found
char.IsDigit, char.IsNumber Returns a nonzero value when a decimal value (0-9)
is found
char.fsLower: Returns true when a lowercase alphabetical
character is found
char.lsPunctuation Returns true when a punctuation mark is found
char.W hiteSpace Returns true when a w hitespace character is found
char.IsUpper Returns true when an uppercase alphabetical
character is found

T able 4.2. D ata co m p a riso n fu n ctio n s.

In the ancient times, many of the primitive C programmers


fell victim to an unspeakable evil known as the Malloc.

From Strings to Streams: System.10


In addition to storing and retrieving simple character strings, we can also widen our perspec­
tive by beginning to access and write to files via our floppy and hard drives. The use of file
manipulations also includes the addition of a second reference, System.10, which enables the
use of two key file related methods: StreamReader and StreamWriter. These methods, as
their names imply, allow us to read and write to those files. The files in question need to be
opened and closed separately, that is, one reference is used to identify the file as a storage device
and one to retrieve that data. As with many of the object-based functions, our data streams also
offer a host of member accessible functions th at will be explored as we uncover the Base Class
Library. The correct procedure for accessing these methods always includes an opening state­
ment, a reading or writing to statem ent, and the closing method (see Table 4.5). Note th at
forgetting to close these files will produce a runtim e error.

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; }

T able 4.3. S trea m R ea d er and Stream W riter.

Exampling Object Types


A nother im portant point w hen working w ith object types involves the use of extensions,
which are m ethods th a t allow us to m an ip u late objects, including E q u a l s ( ),
G e t H a s h C o d e (), G e t T y p e (), and T o S t r i n g () . The use of extensions can determ ine a
host of inform ation and th u s simplify our tasks (see Table 4.4).

CTS Type Description


Boolean bool Determines whether the specified Object is equal to the
Object.Equals(object obj) current Object
Boolean bool Serves as a hash function for a particular type, suitable for
Object.GetHashCode (object obj) use in hashing algorithms and data structures like a hash
table
Boolean bool Gets the type o f the current instance
Object.GetType(object obj)
Boolean bool Returns a string that represents the current object
Object.ToString(object obj)

T able 4.4. E x te n sio n s.

The Keywords checked and unchecked


Another weakness when programming in other computer languages is their inability to pro­
tect against arithmetic overflows. An arithmetic overflow occurs when a variable of a numeric

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.

E xam p le 4.38. The k ey w o rd c h e c k e d .


using System;

namespace Chapter4 {
class Classl {
static void Main() {
byte Max255 = 255;

Max255++; // this error will go undetected

checked { // This error will call an exception at run-time


Max2 55 + +;
}

Qte Edit tfevr eroject guid Qebug loots Window Hefe

1 0 f ' - ' J ►Oefcug - G#" iff *


_ ... 1 jA % % % .
Start Page :
ConsoteAppUcation2 P rop erty Pages

Configuration: |Actlv«<Mtwg) t j gbtform: |a<*»v«(.NET)... Cgpfiguration Manager...

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

Check for Arithmetic Overflow/Underflow


Check aS integer arithmetic for out of bounds results (/checked).

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.

E xam p le 4.39. A c h e c k e d com p iler.


using System;

namespace Chapter4 { '


class Classl {
static void Main () {
byte Max255 = 255;
Max255 += 1; // this error will call an exception at run time

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).

E xam p le 4.40. An u n c h e c k e d com p iler.


using System;

namespace Chapter4 {
class Classl {
static void Main() {
byte Max255 = 255;
unchecked {
Max255 += 1; // this error will go undetected
}
}
}
}

The g o to Statem ent


The g o to statem ent is probably the m ost picked-on of all the keywords. Its use is consid­
ered a poor program m ing habit, yet somehow it m anages to endure. Its fault lies in its
ability to transgress order—the C# help files even m ark it as a useful way of getting out of
nested statem ents, but, of course, th a t would be breaking the rules. Still, there is a t least

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).

E xam p le 4.41. The g o t o sta tem en t.


using System;

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") ;

}
}

Game 4 —Battle W ave


We will now proceed a bit further into the evolution of a game. Using combined knowledge
of arrays and pointers, we are finally free to use both m ultiples of objects and arrays of
inform ation determ ining those m ultiples. We are also able to shortcut these procedures

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.

E xam p le 4.42a. B ra in sto r m in g B a ttle W ave.

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 .

Drawing Characters and Defining Motions


Once again, we will create our characters using the graphics portion of the compiler. The
alien ships will move in unison, trotting along the x-axis with additional movements along
the y-axis w hen the furthest aliens reach either side. Our player’s character, by contrast,
will only be able to move along the x-axis using the left and right arrows on the num eric
keypad with the spacebar used to enable its weapons (see Example 4.42b).

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.

E xam ple 4.43. A lgorith m for B a ttle W ave.

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.

Inside the Gam ing Loop:


8. Reset aliens to begin new level(s).
9. R estore/test and display high scores.
10. Display characters.
11. Read keyboard inputs.
12. Track weapons.
13. Test for collisions.
14. Play three sounds while the game is running: W eapon’s fire, ship
movement, and explosion...
15. Test of lim itations (walls).
16. Move characters.
17. Clear screen.

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

It is important to remember that DirectX requires our graphic files to be stored


as bitmaps, and that, while Forms can also use bitmaps, most Windows’ Forms
programmers prefer to use the lower-resolution graphic file formats such as
JPEGs to save resources. It is also im portant to remember that these
distinctions are merely a matter of storage type and that they do not affect the
steps used to draw our images. This text’s CD-ROM, for example, includes
both .JPG and .BMP images, which were created as bitmaps and then resaved
under the JPEG format.

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

BW Microsoft Visual O .NET [design] media\Target19.bmp


Bte £<k flaw 0roj6ct guild Qebug loots Image &ndow Help
IP * t U 0 * H& ® ►Retease * j |# onpaW ’ 3 0 1 0 T
a ^ a \ £>• \ A □ • > * .
% Colors JJl X jWavs.cs [Design] (tettteWave.-ts i medatTnraoW.hmp I medtefTargeUMmp medta\Targetl9i>mp | *edto‘< ►X j

S k e tc h e d D esig n 4.1 Bulb.

» BW Microsoft Visual C£ .NET [design] - media\Target12.bmp


File Edit. View Project gu8d Debug lods image Window Help

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 < >

S k e tc h e d D e sig n 4.2. Frog.

274
Chapter 4: Arrays, Pointers, and Strings

» BW Microsof! Visual C" .NET [design] mcdia\Target6.bmp


0e Ed* View Eroject 6utt Cebu? loots Image Mndow Help
<P’ : ► - * cnpaM *!9 CfSfi
Kr \ ■> A D l » 0 « » o « # . - - * Cl.
<% Colors_______________ fl_ X med«\Targe'?.bmp media\Target6.bmp | medus\Targeti9.bmp ; mettoVlargefl8.bmp ! rritdia\Targe’ i ►
#\ m111 I I I
mm ii
lino

Ready
--------
| / start C2new.doc - Microsof... 8W - Microsoft Visual t-C4j.bmp • Ratnt 4k ' irKPM j

S k e tc h e d D e sig n 4.3. R obot.

* BW Microsoft Visual Cr .NET[design] inediaVTarget0.bmp


9e Ed* Sew Project EMM Qebug loots Image Vflndow [jelp
ijjp - 1 ■ Or i 0 £ % H <£1 • ' i > Release - onpaint •:3sS»!a
1t”'i J (7]<**t\7AaB»o®»o®«» ,* ,
% Colors If- X r . v - medajfargetU bmp medaITargetlQ.bmp - e . i i . - : media\Target0.bmp I 4

"'«■ M
□□
• T • *8 «*

' I 'i t o v ''

S k e tc h e d D e sig n 4.4. E ye.


C# and Game Programming

» RW • Microsoft VisunlCe .NET [design] - mediii\Bomb0.hmp


file Mt View Project Quid Debug Toed Image Window Help

&3♦v a?HflP ffet? ' <£>*% ►


«<*»*= * 1#°"P«<
j a <5* 0 ’ \J]<? t \ ) A ■ i C ,
ijCdors ijL X i 'leri Po.je r,.«i1eW»ve.cs(De^; BetlH'Vw , me<*a\Bo»nb0.tHT*> |
Illllll
MM MU

S k e tc h e d D e sig n 4.5. Bom b.

E»s Ed* flew Project guild Qebug loots (mage Window Help

£) * s a? B 9 A fe <P • * 1 # °"p*< aeff'SS ”


!a q j a %p -;[/]« ? A

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

S k e tc h e d D e sig n 4.6. G us (th e H ero).

276
Chapter 4: Arrays, Pointers, and Strings

fife Ed* View groject fiutt (Jebug Tools Image Window

m- -&a a :m%m ► * * 3l?f^ -


a q J a 4*&, ^ \ ) A □■ ■I : A €u.............
.mmmmmum
% ijCofc»*..............................? X H ‘.>iwt i'oije fiVHeW.yve.es [Osgn} BsWeWsvt.cs .bmf media\Rocl<et0.bmp | <1 > X |

| D” O: M n: m * n w m

t Start 3S'f2new<toe-Moose#. . * i BW-ffoosoftVeusI E-C4d.bmt> •»><*«

S k e tc h e d D e sig n 4.7. M issile.

Alternative Rendered Designs

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)

R en d ered D e sig n 4.1. A lie n l.

277
C# and Game Programming

Alien 2 p i (x-10, y-10)


pl2 (x+5, y+10)
p2 (x-5, y-10)
2 pl3 (x+5, y+5)
21 5 p3 (x-5, y-5)
9 H pl4(x-5, y+5)
p4 (x+5, y-5)
19 B pi 5 (x-5, y+10)
p5 (x+5, y-10)
p l6 (x-10, y+10)
p 6 (x+10, y-10)
IB R p l7 (x-10, y+5)
1H 13 p7 (x+10, y-5)
p l8 (x-5, y+5)
k— —i p8 (x+5, y-5)
1G 15 12 p l9 (x-5, y-5)
p9 (x+5, y+5)
p20 (x-10, y-5)
plO (x+10, y+5)
p21 (x-10, y-10)
p ll (x+10, y+10)

R en d ered D e sig n 4.2. A lien 2.

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)

R en d ered D e sig n 4.3. A lien 3.

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)

R en d ered D e sig n 4.4. A lien 4.

278
Chapter 4: Arrays, Pointers, and Strings

Our hero is rep resen ted a s a sim p le pie shape, e .g ., g . F i l l P ie (B r u s h e s . B lu e ,


p 1a y e r . imagePosX, p1a y e r . imagePosY, p l a y e r . imageWidth,
p l a y e r . i m a g e H e ig h t , 65, 50);.

R en d ered D e sig n 4.5. The H ero.

Animating Characters: Displaying Characters

W e ll u se a sim p le O n P a i n t fu nction to draw our characters, w hich w ill include th e ship,


th e w eapons, and all of th e alien crafts. N otice how I’ve changed the colors on the draw ings
to g ive th em a d istin ct look; you sh ou ld also notice th e colorful p a ttern s (see E xam ple
4.44).

E xam p le 4.44. D ra w in g B a ttle W ave ch a ra cters.


// Draw the scores
buffer.ColorFill(Color.Black);
buffer.ForeColor = Color.Blue;
if(player.score < HighScore) {
buffer.DrawText(4 * SCALE, 2*SCALE, HighScore.ToString () , false);
} else {
buffer.DrawText (4 * SCALE, 2*SCALE, player.score.ToString () , false);
}

buffer.DrawText(16 * SCALE, 2*SCALE, player.score.ToString (), false);

if (player.isActive) {
try {
destination = new Rectangle(player.imagePosX, player.imagePosY,
player.imageWidth, player.imageHeight);
buffer.Draw(destination, PlayerDraw, DrawFlags.Wait);

for (int i = 0; i < NUM MISSILES; i ++) {

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 );

for (int i = 0; i < NUM_TARGETS; i + +) {


if (t a r g e t s [i ].isActive){
try {
destination = new R e c t a n g l e (t a r g e t s [i ].imagePosX,
targets[i].imagePosY, targets[i].imageWidth,
t a r g e t s [i ].imageHeight);
b u f f e r .Draw(destination, T ar g e t D r a w [i ], Draw Fl ag s.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 ();

Animating Our Characters: Patterns of Movement


The aliens’ anim ation is based on a p attern of motion determ ined not by our actions, but by
a predeterm ined set of num bers. This takes us out of th e realm of artificial intelligence
and redefines th eir m ovem ents as simple motion. For this, the function A l i e n C l i c k
represents a list of simple controls (see Example 4.45).

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

Exam ple 4.45. P atterns o f m ovem ent for B attle Wave.


public void MoveTargets(TimedEvent e, Object obj ) {

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;

for (int i = 0; i < NUM_TARGETS; i++) {


if (newDirection != 0)
t a r g e t s [i ].direction = newDirection;

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

t a r g e t s [i ].imagePosX > p l a y e r .imagePosX - 50)) {


F i r e B o m b (i );

Defining Character Limitation


Preventing characters from moving off the screen is ju st a m atter of practicality. Theoreti­
cally, the game could be played off the screen, but this would m ake little sense. Also, since
there are lim its to the range of our characters’ values, it is foreseeable th a t if a character
was left to run amuck, it could exceed those values and cause an error (see Examples 4.46
and 4.47).

E xam p le 4.46. C h aracter lim its (from A n im a te d lm a g e.e s).

// Moves the image to be within the specified boundary.


// Returns whether any position changes were made,
virtual public bool C o n s t r ai nT oB ox () {
bool retVal = false;

if (!isActive)
return false;

if (imagePosX < constrai nt Bo x.X) {


imagePosX = constra in tB ox .X;
retVal = true;
} else if ((imagePosX + imageWidth) >
(c onstraintBox.X + c onstraintBox.W i d t h ) ) {
imagePosX = constra in tB ox .X +
c ons tr aintBox.Width - imageWidth;
retVal = true;
}

if (imagePosY < constrai nt Bo x.Y) {


imagePosY = const ra in tB ox .Y;
retVal = true;
} else if ((imagePosY + imageHeight) >
(constraintBox.Y + c onstraintBox.He i g h t )) {
imagePosY = co ns tr aintBox.Y +
co ns tr aintBox.Height - imageHeight;
retVal = true;
}

282
Chapter 4: Arrays, Pointers, and Strings

return retVal;
}

Exam ple 4.47. Character and projectile constraints.

// 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 ;

// Initialize player's missiles


playerMissiles = new Animatedlmage[NUM_MISSILES];
for (int i = 0; i < NUM_MISSILES; i + +) {
playerMissiles [i ] = new Animatedlmage (0, 0) ;
playerMissiles [i ] .owner = player;
playerMissiles [i ] .constraintBox = ClientRectangle;
p l a y e r Mis si le s[i ].Re sc a l e l m a g e (SCALE / 2, SCALE / 2);

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).

E xam p le 4.48a. K eyboard c o n tro ls for B a ttle W ave.

private void Keyboard_Tick(object sender, S y s t e m .EventArgs e) {


M icr os o ft.D ir ectX.DirectXException.IgnoreExceptions();

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 ();

KeyboardState state = k ey bo ar d.G etCurrentKeyboardState() ;

283
C# and Game Programming

for (Key k = Key.Escape; k <= K e y .Me diaSelect; k++) {


if (state[k ] )
p l a y e r .isActive = true; // revive player when any key pressed

if (state[k] && (k == Key.Left || k == K e y .LeftArrow)) {

Force Feedback Controls

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).

E xam p le 4.48b. F orce F eed b a ck k ey com p o n en ts.

private void Joystick_Tick(object sender, S ys t e m .EventArgs e) {


Microsoft.DirectX.DirectXException.IgnoreExceptions();
if (gameState.currentState == G am e S t a t e .S t a t e .Stopped)
r eturn;

foreach (Deviceinstance instance in


M a n a g e r .G e t D e v i c e s (D ev ic eClass.G ameControl,
En umDevicesFlags.A tt achedOnly)) {

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;
}

if (joystick == null) {return;}

joystick.SetDataFormat(DeviceDataFormat.Joystick) ;

284
Chapter 4: Arrays, Pointers, and Strings

foreach (DeviceObjectlnstance d in j oy st ic k.O b je ct s) {


if ((0 != (d.Objectld & (int)DeviceObjectTypeFlags.Axis))) {
joystick.Properties.S e t R a n g e (P ar am eterHow.Byld,
d.Objectld, new InputRange (-1000, 1000));
}
}

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;

bool Joystick = false;

if (-400 < JState.X) {


p l a y e r .direction = Animatedlmage.WEST;
Joystick = true;
} else if (-500 > JState.X) {
p l a y e r .direction = A n im at ed lm ag e.EAST;
Joystick = true;
}

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();
}

byte[] buttons = J S t a t e .GetButtons ();


foreach (byte b in buttons) {
if (0 != (b & 0x80)) {
for (int i = 0; i < NU M_MISSILES; i++) {
if (playerMissiles [i] .isActive == false &&
p l a y e r .isActive) {
F i r e Mi ss il e();
break;
} else if (!p l a y e r .isActive)
p l a y e r .isActive = true;
}
}
}
}

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).

E xam p le 4.49. A lien w e a p o n s fire.

private void FireBomb(int index) {


// d o n ’t shoot at a dead player
if (!t a r g e t s [in d e x ] .isActive || !p l a y e r .isActive)
return; // Dead guys can't fire

if(!targetMi ss il es [in d e x ] .isActive) {


targe tM is si le s[i n de x].isActive = true;
ta rg et Mi ss il es [i n d e x ] .direction = A n i m at ed lm ag e.SO UT H;
targe tM is si le s[index].imagePosX =
ta rgets[index].imagePosX;
targe tM is si le s[i n de x] .imagePosY =
targets[index].imagePosY;

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;

public void MoveBomb(TimedEvent e, Object obj) {


if (gameState.currentState == Ga m e S t a t e .S t a t e .Stopped) {
e.isActive = false;
return;
}

Animatedlmage bomb = (Animatedlmage) obj;


if (!b o m b .isActive) {
e.isActive = false;
}

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).

E xam p le 4.50. R e se ttin g B a ttle W ave.


private void NextLevel() {
if (gameState.currentState != Ga m e S t a t e .S t a t e .Started)
return;

g a m e St at e.currentSpeed++;
timer .ChangeStep (11targets " , gameState .currentSpeed < 10 ?
10 - g a m e St at e.currentSpeed : 1);

for (int i = 0/ i < NUM_MISSILES; i + +)


pl ay er Mi s s i l e s [i ].isActive = false;

for (int i = 0; i < NUM_TARGETS; i + +) {


t a r g e t s [i ].isActive = true;
targe tM is si le s[i ] .isActive = false;

t a r g e t s [i ].imagePosX = ((i % 5) + 1 ) * 2 * SCALE;


t a r g e t s [i ].imagePosY = ((int)(i/5) + 1 ) * 2 * SCALE + 10;

Saving and Retrieving Data


As done previously, we’re going to give players the challenge of trying to defeat a high
score. Again, th is can be done through the use of the l o a d and s a v e functions, which
w ere not listed in the previous chapter. H ere you’ll notice th a t we used an a rra y to
store the nam e of the file, including its extension (see Exam ples 4.51 and 4.52). Note
th a t this function requires the included file <fstream .h>; also if no file is available, the
high score will read zero. These values are also displayed using a modified version of our

287
C# and Game Programming

basic display function. The key changes here include a string value and a decimal output
(see Example 4.51).

E xam ple 4.51. D isp la y in g h ig h scores.


public void SaveHighScore (int score) {
StreamWriter file = null;

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 (); }
}

Expanding Our Arsenal


It would also be useful if we included secondary weapons, m ulticolored of course. These
missiles/rockets could be program med to give off different sounds, run a t different speeds,
and could have varying striking ability, but those task s are up to you. However, keep in
mind your processor’s limitations: Remember, the more objects on the screen, the choppier
the game play (see Example 4.52).

E xam p le 4.52. O p tion s for w ea p o n s.


private void FireMissile () {
if (!p l a y e r .isActive)
return;

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

p lay er M i s s i l e s [i ].imagePosX = p l a y e r .imagePosX;


p l a y e r M is si le s[i ].imagePosY = p l a y e r .imagePosY;

missileEvent = t i m e r .g e t E v e n t ("playerMissile" + i);


m is si l e E v e n t .isActive = true;

B a ttle W ave: The H e a rt of th e Gam e


Once again, we’ll need to weave together a m anaging subprogram th a t is both subject to
our m ain m enu and capable of controlling the plethora of functions listed in the last two
chapters. Remember to include all the proper included and subprograms, and to link to the
object-oriented model we began to develop in C hapter 3 (you may also use project4 to
shortcut these steps—see Example 4.5 3/Battle Wave on the CD-ROM).

Gam e 5 —B a ttle Tennis


We can also modify the last game to reflect another arcade classic, w hat we’ll call B attle
Tennis. This tim e we’ll skip m ost of th e basic steps and include only the essentials.
W hat we’ll w ant is to do is change all of the characters into household breakables like a
lam p, window, TV, and potted plant. We’ll also w ant to remove th eir ability to move and
attack , since household item s don’t really do th a t. Finally, we’ll w ant to replace our
m issiles w ith the tennis ball developed in the first game.

E xam p le 4.54. B r a in sto r m in g B a ttle T en n is.

1. First, we’ll w ant to choose a few household item s, for this


exam ple I chose a TV set, window, plotted plant, and a lamp.
2. Now, we’ll w ant to give them the sam e rainbow color pattern .
3. Next, we’ll w ant to in sert these characters into the last gam e’s
engine, rem em bering to delete the AI portion of th a t game.
4. L et’s replace the basic m issile designs w ith the motion of the
tennis ball found in the first game. Remember, we’ll have to

289
C# and Game Programming

change the p a tte rn of motion of the ten n is ball to work from a


vertical reference point.
5. L et’s include a few sound changes...
6. Finally, we’ll w ant to reverse the d eath cycle, m aking blocking
the ball the right action and avoiding the ball the penalty.

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.

Tennis Microsoft Visual C£*,N£T f design] Yellow Window, bmp [_ iePjjX

- KSa - G» Q a * fe fe ! w ' 4B * & ► Release - // . ^ & & »


§d* View &oje<± §,Jd Qebug look Image Window Help

;a 1 0 **P ’ \7}<? \ ■? A □ ■ * a ® « o • •> ■ - » # „


f e jt ji Start Page ! Pormj.cs [OesNjn] j Ctessi.cs | Pcxmi.cs YdtowWindow.bmp | YefcwTV.bmp I 'tetewHaw U o Yalowlar.^.bwp j O x

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

gp• ta - a? a & m^ & *& ►


r^ - m j/ *
£<* *ie w P roject g rid Qebug loo ts [m age ftin d o w tietp

a c- j a [[}<$ ^ \ ■> A _______


9 X Start Page ! Fo rm l.cs [Design] \ Classi cs | Form l .cs j Y e to w W h dw .bm p YefowTV fcm( Y e B o w P ta n t-b m p | Y eb.vla m p.bm p .

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 ) ;

- M irmsnft Visual f . r NTT [ripsign] Ypllnw T’/ hmp

- 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

i Start a MyUwM*.*M . lerinis -Mjcrcsofcvts... 1:41 PM

public void TV(Graphics g, Brush bTVColor, Pen pTVColor) {


Brush GrayBrush = new So lidBrush(Color.G r a y );

g .FillRectangle(GrayBrush, t h i s .imagePosX, // console


t h i s .imagePosY, 25, 15);
g .FillEllipse(bTVColor, t h i s .imagePosX+1, // tube
t h i s .imagePosY+1, 15, 13);
g .FillEllipse(bTVColor, t h i s .imagePosX+18, // 1st dial
t h i s .imagePosY+2, 5, 5);
g .FillEllipse(bTVColor, t h i s .imagePosX+18, // 2nd dial
t h i s .imagePosY+7, 5, 5);
g .DrawLine(pTVColor, t h i s .imagePosX+12, t h i s .imagePosY, // ant. left
t h i s .imagePosX+5, t h i s .imagePosY-5);
g .DrawLine(pTVColor, t h i s .imagePosX+14, t h i s .imagePosY, // ant. right
t h i s .imagePosX+19, t h i s .imagePosY-5);

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

public void Lamp(Graphics g, Brush LampColor, Brush LampshadeColor) {


P o i n t [] DrawLamp = t h i s .sharpTriangle ();
P o i n t [] DrawLampshade = t h i s .T r a p e z o i d ();
g .FillPolygon(LampColor, DrawLamp);
g .FillPolygon(LampshadeColor, DrawLampshade);
}
We’ll tie these images together in a simple O nPaint function (see Example 4.55).

E xam p le 4.55. O n P ain t fu n c tio n for ob jects o f B a ttle T en n is.


protected override void O n P a i n t (PaintEventArgs e) {
// Write start-up text if game is stopped
if (gameState.currentState == G am eS t a t e .S t a t e .Stopped) {

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);
}

b u f f e r .D r a w T e x t (16 * SCALE, 2*SCALE, p l a y e r .s c o r e .ToString () ,


false);

// Draw the player


try {
destination = new R ec ta ngle(player.imagePosX,
p l a y e r .imagePosY, p l a y e r .imageWidth, p l a y e r .imageHeight);
b u f f e r .Draw(destination, PlayerDraw, D ra wF la gs .W a i t );

// Draw the ball


if (theBall.isActive) {
try {
destination = new R ectangle(theBall.imagePosX,
t h e B a l l .imagePosY,
t h e B al l.imageWidth, t h e B al l .imageHeight);
b u f f e r .Draw(destination, TheBallDraw, D ra wF la gs .W a i t );

// Draw the targets


for (int i = 0; i < N UM_TARGETS; i++) {
if (targets[i ].isActive) {
try {
destination = new Rectang le (t ar ge ts [i ].imagePosX,
targets[i].imagePosY, targets[i].imageWidth,
t a r g e t s [i ].imageHeight);

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 );

p r i m a r y .Flip(buffer, FlipF la g s.DoNotWait);


b u f f e r .Dispose ();

Input Devices: Keyboard, Joystick, and Mouse


Once again, we’ll w ant to give our players movement. The Keyboard will hold the standard
direction, anim ation, and constraint m ethods, as will the Joystick. Here, the Mouse is
used again as Battle Tennis offers sim ilar tennis-like movement, the m ain different being
the lateral calibrations.

E xam p le 4.56. K eyboard c o n tro ls for B a ttle T en n is.


private void Keyboard_Tick(object sender, S y s t e m .EventArgs e) {
Mi cr os of t.Di rectX.DirectXException.IgnoreExceptions();

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 () ;

KeyboardState state = key bo ar d.G etCurrentKeyboardState();

for (Key k = Key.Escape; k <= Key.MediaSelect; k++) {


if (state[k] && k == Key.Left) {
p l a y e r .direction = A n i m at ed lm ag e.WEST;
p l a y e r .Animate ();
p l a y e r .C o n st ra in To Bo x();
if (t h e B a l l .isActive == false)
I nv al id at e();
break;

E xam p le 4.57. J o y stic k c o n tro ls for B a ttle T en n is.


private void Joystick_Tick(object sender, Sy s t e m .EventArgs e) {
Microsoft.DirectX.DirectXException.IgnoreExceptions();

295
C# and Game Programming

if (gameState.currentState == G a me S t a t e .S t a t e .Stopped)
return;

foreach (Deviceinstance instance in


M a n a g e r .G e t D e v i c e s (De viceClass.GameControl,
En u mDevicesFlags.Attach ed On ly )) {
joystick = new
M i c r o s o f t .Di r e c t X .Di re ctlnput.Device(instance.InstanceGuid);
break;
}

if (joystick == null) {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;

if (-400 < JState.X) {


p l a y e r .direction = A n im at ed lm a ge .WEST;
} else i f (-500 > JState.X) {
p l a y e r .direction = An im at ed lm a ge .EAST;
}

byte[] buttons = J S t a t e .GetButtons ();


if (theBall.isActive == false &&
g am eS t a t e .currentState != G a m e S t at e.S t a t e .Stopped) {
foreach (byte b in buttons) {

296
Chapter 4: Arrays, Pointers, and Strings

if (0 != (b & 0x80)) {
FireBall();

E xam p le 4.58. M ouse co n tro ls for B a ttle T en n is.


private void Mouse_Tick(object sender, S y s t e m .EventArgs e) {
Mi cr os of t.Di rectX.DirectXException.IgnoreExceptions();
mouse = new M i c r o s o f t .D i r ec tX .D ir ectInput.D e v i c e (Sy stemGuid.M o u s e );
MouseState mouseData = new MouseState ();

m o u s e .S etD ataFormat(DeviceDataFormat.M o u s e );
mouse.Acquire ();
m o u s e .Poll ();

// Get the current state of the mouse device.


mouseData = m o u s e .CurrentMouseState;

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();

byte[] buttons = m o u s e D a t a .GetMouseButtons ();


if (0 != buttons[0] && !t h e B a l l .isActive) {
FireBall ();
}

The Properties of Sound

In C hapter 3 we looked a t the fundam entals of DirectSound. There, we studied the


basics of creating a sound device and setting its cooperative level, as well as the basics of
execution. In this section, we’ll study the BufferDescription’s properties used to modify our
sounds. The BufferDescription method is used to initializes a new instance of an object (see
Table 4.5).

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

M u t e 3DAtMa xiumDistance A read/write Boolean property, used to determine if a


sound has exceeded its maximum distance (used with
software only).
P rimaryBuffer A read/write Boolean property, used to determine if a
buffer is a primary buffer.
StaticBuffer A read/write Boolean property, used to determine
hardware availability (if available buffer is placed in
hardware, if not the buffer is placed in software).
C ontrolEf f ects must equal false.
StickyFocus A read/write Boolean property, used to determine if a
buffer uses sticky focus. StickyFocus allows for
sound play whenever DirectSound is not engaged.
WaveFo rmat A read/write WaveFormat property specifies the wave
format o f our stored audio data.

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).

Using Sound Effects

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).

E xam p le 4.59. 3D and so u n d effe c ts.


// DirectSound3D
private Micr os of t.DirectX.DirectSound.Device sound = null;
private SecondaryBuffer SoundBuffer = null;
private Buffer3D SoundBuffer3D = null;

sound = new Micr os of t.Dire ct X.DirectSound.D e v i c e () ;


sound.SetCooperativeLevel(this, CooperativeLevel.Priority);

BufferDescription desc = new BufferDescription ();


d e s c .Control3D = true;
d e s c .GlobalFocus = true;

SoundBuffer = new SecondaryBuffer(MEDIA_ROOT + "NextLevel.wav", sound);

301
C# and Game Programming

SoundBuffer3D = new B u f f e r 3 D (SoundBuffer);


SoundBuffer.P l a y (0 , BufferPlayFlags.Default) ;
SoundBuffer3 D .Position = new Vector3(-0.2f, O.Of, l.Of);

SoundBuffer = new SecondaryBuffer(MEDIA_ROOT + "Racket.wav", sound);


EffectDescription[] effects = new EffectDescription[1];
e f f e ct s[0].GuidEffectClass = DSoundHelper.StandardGargleGuid;
SoundBuffer.SetEffects(effects);
SoundBuffer.P l a y (0, BufferPlayFlags.Default);

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).

E xam p le 4.60. N ex t lev e l.


private void N e x t L e v e l () {
try {
// DirectSound3D
SoundBuffer = new SecondaryBuffer(MEDIA_ROOT + "NextLevel.w a v " ,
sound );
SoundBuffer3D = new Buffer3D(SoundBuffer) ;
Sound Bu ffe r.P l a y (0, Bu ff er PlayFlags.Default);
S oundBuffer3D.Position = new V e c t o r 3 (-0.2 f , O.Of, l.Of);
} catch {
U t i l s .PlaySound(MEDIA_ROOT + "NextLevel.WAV");
}
for (int i = 0; i < NU M_TARGETS; i++) {
targets [i] .isActive = true;

E xam p le 4.61. P r o jec tile a n im a tio n .

public void MoveBall(TimedEvent e, Object ob j ) {


if (gameState.currentState != G am eS t a t e .S t a t e .Started)
return;

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

if (theBall.imagePosY + t h e B a l l .imageHeight >=


C li en tS iz e.He ig ht ) {
p l a y e r .deaths++;
t h e B a l l .isActive = false;

if (player.deaths >= NUM_LIVES) {


g a m eS ta te .currentState = G a m e S t a t e .S t a t e .Stopped;
if (player.score > HighScore)
SaveHighScore(player.score);
C u r s o r .S h o w ();
A pp l i c a t i o n .E x i t ();

t h e B a l l .D e f l e c t () ;
return;

Completing the Game


Finally, we’ll w ant to build our m anaging or m ain program . Rem em ber to include the
DirectX and Game Classes (see Example 4.62/BattleTennis.cs on the CD-ROM).

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.

Common Errors, Problems and Pitfalls


1. If the gam es are compiling, but you get a runtim e error and/or
you only detect the default sound, th is indicates th a t your
references are not to the appropriate director. For example, if
you’ve copied a game to your D : \ \ drive, th en C : \ \ listings

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

6. B inary searches tend to be faster w hen working w ith longer lists


of d a ta and they are the preferred m ethod w hen w orking w ith a
longer list th a t requires repeated searches. (Note: Binary
searches m ust be sorted before they can be tested).
7. Pointers are usually assigned to variables, bu t they can also be
assigned to the values zero and null.
8. The am persand symbol is required w hen assigning pointers to
variables, b u t it is not required w hen assigning pointers to
pointers or w hen passing an array.
9. An a rra y is a constant equivalent to a pointer address.

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

14. W rite a program th a t displays the word “world” using a pointer


string.
15. Revise th a t last program , allowing the pointer to be passed
before the word is displayed.
16. W rite a program th a t allows the user to add, subtract, multiply,
divide, and find the rem ainder of two integers.
17. Use pointer arithmetic to move from one point in an array to another.
18. W rite a program th a t begins w ith a void pointer, but th en assigns
th a t pointer to the four basic d a ta types.
19. W rite a function th a t re tu rn s a value as a pointer.

307
Object-Oriented
Design

I f I have seen farther than others, it is because I


was standing on the shoulders o f giants.
-Isa a c Newton

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#.

E xam p le 5.1. A sim p le stru ctu re.


using System;

namespace Chapter5 {
struct BankAccount {
string first_name;
string last_name;
long account_number;
decimal Checking;
decimal Savings;
short pin_number;

static void Main() {


BankAccount Balance;
B a l a n c e .account_number = 1234;

Console.WriteLine(Balance.account_number);
}
}
}

Declaring and Assigning Fields


Fields are not declared and assigned values directly; rather, they are declared as objects
through the use of instances and are assigned as a combination of those instances and
th eir referencing points. The com bination of term s is m arked by a connecting dot as the
m em ber selection operator (.), which is necessary because fields are essentially general­
ized variables th a t can be used for m ultiple purposes. Thus, the use of assignm ent sta te ­

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).

E xam p le 5.2. D e c la r in g an d a s s ig n in g stru ctu res.


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;

public static void M a i n O {


BankAccount account;
C ons ol e . W r i t e ("Enter your pin number here (2001): ");
a c c o u n t .pin_number = s h o r t .Parse(Console.ReadLine ());

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.

E xam p le 5.3. D e c la rin g and a s s ig n in g m u ltip le in sta n c e s.

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;

C o n s o l e .W r i t e ("\nEnter your pin number here: ");


short input = s h o r t .Parse(Console.ReadLine ());

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).

The keyword new is used as both an operator and a modifier. As an operator, it


is used to declare instances and to create objects. As a modifier, it is used to
hide members inherited from a base class. The new operator cannot be
overloaded or used with an override statement.

E xam p le 5.4. A rrays o f str u c tu r e s.


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 {
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

E xam p le 5.5. N e sted str u c tu r e s.


using System;

namespace Chapter5 {
struct BankAccount {
public string first_name;

public struct NestedStruct {


public decimal swiss_account;
}
}

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;
}
}
}

Structures as Function Arguments: Calls-by-Value


In addition to being able to pass our standard variables as both call-by-value and call-by-
reference values, we can also pass fields using eith er of these techniques. In this section
we’ll apply the sim pler of the two, the call-by-value procedure, for which we’ve already
defined the self-contained n atu re of those values. Remember, calls-by-value are used to
pass data th a t is m utable from w ithin th a t referencing method, but which ultim ately does
not affect the source values (see Example 5.6).

E xam p le 5.6. C alls-by-valu e w ith str u c tu r e s.

using System;

namespace Chapter5 {
class Classl {
struct BankAccount {
public string first_name;

316
Chapter 5: Object-Oriented Design

public string last_name;


public long account_number;
public decimal checking;
public decimal savings;
public short pin_number;
}

static void Main() {


BankAccount account;

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;

C o n s o l e .W r i t e ("Enter you pin number now: ");


input = s h o r t .Pa rs e(Console.R e a d L i n e ());

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);
}
}

static decimal function(decimal balance) {


decimal input;
C o n s o l e .W r i t e L i n e ("Your current balance: {0}", balance);
Co ns ol e . W r i t e ("\nAmount to deposit: ");
input = d e c i m a l .Parse(Console.R e a d L i n e ());
balance = balance + input;
return (balance);
}
}
}

317
C# and Game Programming

Structures as Function Arguments: Calls-by-Reference


Next, we will pass fields using a call-by-reference procedure. Call-by-reference procedures
are, simply put, limited pointer values. Any alterations in the passed variable’s values now
a lte r the m em ber’s stored values. These, like th eir variable counterparts, are also refer­
enced w ith the keywords r e f and o u t as shown below (see Exam ple 5.7).

E xam p le 5.7. C alls-b y-referen ce w ith str u c tu r e s.


using System;

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;
}

static void Main () {


BankAccount account;

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);

Conso le .W ri te Li ne ("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 .c hecking);

318
Chapter 5: Object-Oriented Design

static void function(ref decimal balance) {


decimal input;
C o n s o l e .W r i t e L i n e ("Your current balance: {0}", ba la n c e ) ;
C o n s o l e .W r i t e L i n e ("Amount to deposit: ");
input = d e c i m a l .Parse(Console.R e a d L i n e ());
balance = balance + input;

Passing Entire Structures


In addition to being able to pass single stru c tu ra l m em bers, we can also pass an entire
structure using a call-by-value or call-by-reference procedure. In both cases, the reasoning
for doing so would involve the increased portability and reusability of such generalized
user-defined functions (see Examples 5.8 and 5.9).

E xam p le 5.8. C alls-by-valu e for e n tir e str u c tu r e s.


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 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

static void function(BankAccount acc) {


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 ar se (Console.R e a d L i n e ());

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);

C o n s o l e .W r i t e ("Enter a new pin number here: ");


a c c .pin_number = s h o r t .P arse(Console.R e a d L i n e ());
Conso le .W ri te Li ne ("Deposit into savings account: ");
input = s h o r t .P arse(Console.ReadLine ());
acc.savings = acc.savings + input;

E xam p le 5.9. C alls-b y-referen ce for e n tir e str u c tu r e s.


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 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);
}

static void function (ref BankAccount acc) {


C o n s o l e .W r i t e L i n e ("Enter your pin number here: ");
short input = s h o r t .Parse(Console.R e a d L i n e ());

if (input == a c c .p in_ number) {


C o n s o l e .W r i t e L i n e ("Account Number: {0}",
acc .account__number) ;
C o n s o l e .W r i t e L i n e ("Iden ti ty : {0} {1}",
acc.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 av ings);
C o n s o l e .W r i t e L i n e ("Checking Account Balance: {0}",
a c c .Ch ec king);

C o n s o l e .W r i t e ("Enter a new pin number here: ");


a c c .pin_number = s h o r t .Parse(Console.R e a d L i n e ());
C o n s o l e .W r i t e L i n e ("Deposit into savings account: ");
input = s h o r t .Parse(Console.R e a d L i n e ());
acc.Savings = acc.Savings + input;

Storing and Retrieving Data


In the last few examples, we altered our u se r’s accounts only to have those alterations lost
at the end of the program. This, of course, would be quite impractical, but it was only done
to simplify the learning process. The next few exam ples include coding techniques th a t
link and store our data for fu rth e r reference after our program s have been term inated.
The processes involved in data storage and retrieval are not actually based on the C#
language, but instead are linked to the Base Class Library. Here, we’ll use the namespace
reference System .10 w ith the instances Stream R eader and Stream W riter and a list of

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.

E xam p le 5.10. S to r in g and r e tr ie v in g data.


using System;
using System.10;

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

C o n s o l e .W r i t e L i n e ("Pin Number: {0}",


accountl.pin_number);
C o n s o l e .W r i t e L i n e ("Account Number: {0}",
a cc ou n t l .account_number);
C o n s o l e .W r i t e L i n e ("Name: {0} {1}",
a cc ou n t l .first_name, a c c o u n t l .last_name);
C o n s o l e .W r i t e L i n e ("savings Balance: {0}",
account1.savings);
C o n s o l e .W r i t e L i n e ("checking Balance: {0}",
a cco u n t l .checking);

SaveFile(accountl, 0, 0) ;
}
}

static void CreateFile(out BankAccount 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 .pin_number = s h o r t .Pa r se(Console.R e a d L i n e ());

Random rnd = new R a n d o m ();

a c c .account_number = r n d . N e x t (1, 100);

C o n s o l e .W r i t e L i n e ("\nYour New Account Number is: {0}",


a c c .account_number);
C ons ol e . W r i t e ("\nEnter your first name: ");
a c c .first_name = C o n s o l e .ReadLine ();
Co ns ol e . W r i t e ("\nEnter your last name: ");
a c c .last_name = C o n s o l e .R e a d L i n e ();
Consol e. Wr it eL in e("\nEnter your savings Balance: ");
acc.savings = d e c i m a l .P arse(Console.R e a d L i n e ());
C o n s o l e .W r i t e L i n e ("\nEnter your checking Balance: ");
acc.checking = d e c i m a l .P arse(Console.ReadLine ());

SaveFile(acc, 0, 0);
}

static void SaveFile(BankAccount acc, short inputl,


short input2) {

StreamWriter file = new StreamWriter(@"C:\MyFile.txt") ;


file.WriteLine(acc.pin_nu mb er );
file.WriteLine(acc.account_number);
f i l e .W r i t e L i n e ((acc.savings + inputl));
f i l e .W r i t e L i n e ((acc.checking + input2));

323
C# and Game Programming

file.WriteLine(acc.first_name);
file.WriteLine(acc.last_name);
f i l e .C l o s e ();

static void ReadFile(ref BankAccount acc) {


StreamReader file = new StreamReader(@"C:\MyFile.txt");
acc.pin_number = short.Parse(file.ReadLine());
acc.account_number = long.Parse(file.ReadLine());
acc.savings = decimal.Parse(file.ReadLine());
acc.checking = decimal.Parse(file.ReadLine ());
acc.first_name = file.ReadLine();
acc.last_name = file.ReadLine();
file.Close ();
}
}
}

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

Exam ple 5.11. A sim ple class.


using System;

namespace Chapter5 {
class BankAccount {
string first_name;
string last_name;
long account_number;
decimal checking;
decimal savings;
short pin_number;

static void Main 0 {


BankAccount Info = new BankAccount ();
I n f o .account_number = 4353;
C o n s o l e .W r i t e L i n e (I n f o .account num be r) ;

The keyword static is used to modify constructors, fields, methods, operators,


and properties. Static constructors, for example, are called automatically and
are used to initialize the rest of the class before any members are referenced.
Static fields, then, are not part of a specific instance and instead are referenced
as a single memory address.

Replacing Structures with Classes


Since classes are declared and assigned in basically the same m anner as structures, and
since we haven’t as yet defined the other access levels, it only m akes sense th a n th a t we
should begin w ith a simple public reference. In addition, if ju st to avoid the monotony of
repeating all of the previous examples, I thought th a t I’d ju st jum p ahead to the final
exam ple given on stru ctu res and modify it ju st enough to represent a working model of
a class (see Exam ple 5.12). Rem ember you m ust first create a file before you can view it.

325
C# and Game Programming

As we examine this program, w e ll find that the most important modification


pertains to the dynamic instance. This change was necessary because classes
are, in fact, referencing data types. You should also notice that the key methods,
namely SaveFiles, CreateFiles, and ReadFiles did not need to be edited
for use with this altered program. This adheres to the principles behind
structured programming, wherein our functions are written as generic coding
that can be reused by several applications; this is also the underlying principle
of object-oriented program, as we will see in the next section.

E xam ple 5.12. S to r in g and r e tr ie v in g d a ta w ith c la sse s.


using System;
using System.10;

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 ());

if (Char.ToUpper (input) == 'C') {


C r e a t e F i l e (ref accountl);
} else if (Char.T o U p p e r (i nput) == 'V') {
ReadFile(ref accountl);
} else {
break;

326
Chapter 5: Object-Oriented Design

C o n s o l e .W r i t e L i n e ("Pin Number: {0}",


a cc o u n t l .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 o u n t l .account_number);
C o n s o l e .W r i t e L i n e (" N am e: {0} {1}",
a c c o u n t l .first_name, ac c o u n t l .last_name);
Consol e. Wri te Li ne ("Savings Balance: {0}",
ac c o u n t l .savings);
C o n s o l e .W r i t e L i n e ("Checking Balance: {0}",
a c c o u n t l .checking);

SaveFile(accountl, 0, 0);
}
}

static void CreateFile(ref BankAccount acc) {


C o n s o l e .WriteLine ("Enter Your New Pin Number: ");
a c c .pin_number = s h o r t .P arse(Console.ReadLine ());

Random rnd = new R a n d o m ();


a c c .account_number = rnd.Next(l, 100);

C o n s o l e .W r i t e L i n e ("\nYour New Account Number is: {0}",


a c c .account_number);
C o n s o l e .W r i t e ("\nEnter your first name: ");
a c c .first_name = 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 ("\nEnter your last name: ");
a c c .last_name = 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 L i n e ("\nEnter Your Savings Balance: ");
acc.savings = d e c i m a l .P ar se(Console.R e a d L i n e ());
C o n s o l e .W r i t e L i n e ("\nEnter Your Checking Balance: ");
acc.checking = d e c i m a l .Parse(Console.ReadLine ());

SaveFile(acc, 0, 0) ;
}

static void SaveFile(BankAccount acc, short inputl,


short input2) {
StreamWriter file = new StreamWriter (@"C:\MyFile.t x t ");
file.WriteLine(acc.piri_number);
f i l e .W ri te Li ne (a cc .account_number);
f i l e .W r i t e L i n e ((acc.savings + inputl));
f i l e .W r i t e L i n e ((acc.checking + input2));

327
C# and Game Programming

file.WriteLine(acc.first_name);
file.WriteLine(acc.last_name);
f i l e .C l o s e ();
}

static void ReadFile(ref BankAccount acc) {


StreamReader file = new S t r ea mR ea de r(@ " C :\MyFile.t x t ");
a c c .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 ();
file.Close ();

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;

public void CreateFile(ref BankAccount 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 .pin_number = s h o r t .Parse(Console.R e a d L i n e ());

Random rnd = new R a n d o m ();


a c c .account_number = r n d . N e x t (1, 100);

C o n s o l e .W r i t e L i n e ("\nYour New Account Number is: {0}",


a c c .account_number);
C on so l e . W r i t e ("\nEnter your first name: ");
a c c .first_name = C o n s o l e .R e a d L i n e ();
C on so l e . W r i t e ("\nEnter your last name: ");
a c c .last_name = 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 L i n e ("\nEnter Your Savings Balance: ") ;
acc.savings = d e c i m a l .Pa rs e(Console.R e a d L i n e ());
Console .WriteLine ("\nEnter Your Checking Balance: 11) ;
acc.checking = d e c i m a l .P arse(Console.R e a d L i n e ());

SaveFile(acc, 0, 0) ;
}

public void SaveFile(BankAccount acc, short inputl,


short input2) {

StreamWriter file = new S t r e am Wr it er (@ " C :\MyFile.t x t ");


f i l e .Write Li ne (a cc .pin _n um b er );
f i l e .Wr it eL in e( ac c.account_number);
f i l e .W r i t e L i n e ((acc.savings + inputl));
file.Wr it eL in e((acc.checking + input2));
file.WriteLine(acc.first_name);
file.WriteLine(acc.last_name);
f i l e .Close ();

public void ReadFile(ref BankAccount acc) {


StreamReader file = new S t r e a m Re ad er (@ " C :\MyFile.t x t ");

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 ();

public void ViewFile(BankAccount acc) {


Conso le .W ri te Li ne ("Pin Number: {0}", a c c .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 c c .account_number)
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 .last_name);
C o n s o l e .W r i t e L i n e ("Savings Balance: {0}", a c c .savings);
Conso le .W ri te Li ne ("Checking Balance: {0}", a c c .checking);

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 ());

if (Char.ToUpper (input) == 'C') {


a c c o u n t .CreateFile (ref ac count);
} else if (Char.ToUpper (input) == 'V') {
a c c o u n t .ReadFile (ref account);
} else {
break;
}

account.ViewFile(account);
a cc o u n t .SaveFile(account, 0, 0);
}

330
Chapter 5: Object-Oriented Design

While private is the default setting, many programmers choose to explicitly


restate that command to remove any ambiguity.
The programs in Examples 5.13 and 5.14 are especially important when dealing
with the migration of thinking from the standard structured programming
model to our modern day object-oriented programming principles. Notice how
the previous sections user-defined functions have been modified to serve as
public methods.

E xam p le 5.14. P r o te c te d m em b ers.


usin g System;
using S y s t e m . 10;

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 ());

R a n d o m rnd = new R a n d o m ();


a c c .a c c o u n t _ n u m b e r = r n d . N e x t (1, 100);

C o n s o l e .W r i t e L i n e ("\nYour Ne w A c c o u n t N u m b e r is: {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 ("\nEnter your first name: ");
a c c .f i r s t _ n a m 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 ("\nEnter your last name: ");
a c c .las t_ n a m 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 L i n e ("\nEnter Your S avi ngs Balance: ");
a c c . s a v i n g s = d e c i m a l .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 L i n e ("\nEnter Your C h e c k i n g Balance: ");
a c c . c h e c k i n g = d e c i m a l .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

SaveF ile (ac c, 0, 0);


}

p u b l i c vo i d S a v e F i l e ( B a n k A c c o u n t acc, short inputl,


short input2) {

S t r e a m W r i t e r file = ne w S t r e a m W r i t e r ( @ " C : \ M y F i l e . t x t ");


f i l e . W r i t e L i n e ( a c c .p i n _ n u m b e r );
f i l e .W r i t e L i n e ( a c c .a c c o u n t _ n u m b e r );
f i l e .W r i t e L i n e ( ( a c c .saving s + inputl));
f i l e . W r i t e L i n e ( ( a c c .c h e c k i n g + input2));
f i l e .W r i t e L i n e ( a c c .f i r s t _ n a m e ) ;
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 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

"<V> to v iew 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 ());

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);

The Internal Access Modifier


An internal access modifier is a type m em ber used to access class components. The
advantage of the in tern al modifier is th a t it allows for lim ited access from w ithin a single
assembly. A key disadvantage is th a t it is only accessible from w ithin th a t assembly. In
addition to the basic in tern al modifier, we can also use the keyword internal in combina­
tion w ith protected to create a internal protected modifier (see Exam ple 5.15).

E xam p le 5.15. In ter n a ls.


usi n g System;
usin g S y s t e m . 10;

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 ;

int ern al v o i d R e a d F i l e s (ref B a n k A c c o u n t acc) {


S t r e a m R e a d e r R e a d F i l e = new S t r e a m R e a d e r (@ " C : \ M y F i l e . t x t ");

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 ();

in ter n a l voi d C r e a t e F i l e s (ref 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 Y our 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 ());
R a n d o m rnd = ne w R a n d o m ();
a c c .a c c o u n t _ n u m b e r = (l o n g ) M a t h .R o u n d ( r n d .N e x t D o u b l e () *
100) + 1;
C o n s o l e .W r i t e L i n e ("\nYour N e w A c c o u n t N u m b e r is: {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 ("\nEnter your first name: ");
a c c .f i r s t _ n a m 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 ("\nEnter your last name: ");
a c c .la s t _ n a m 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 L i n e ("\nEnter You r Sav ing s Balance: ");
a c c . S a v i n g s = d e c i m a l .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 L i n e ("\nEnter Yo ur C h e c k i n g Balance: ");
a c c . C h e c k i n g = d e c i m a l .P a r s e ( C o n s o l e .R e a d L i n e ());
S av eFi les (ac c, 0, 0);

i n te rna l vo i d Sa v e F i l e s (BankAccount acc, short inputl,


short input2) {
S t r e a m W r i t e r Sa v e F i l e = new S t r e a m W r i t e r (@ " C : \ M y F i l e . t x t ");
S a v e F i l e . W r i t e L i n e ( a c c . p i n _ n u m b e r );
S a v e F i l e .W r i t e L i n e ( a c c .a c c o u n t _ n u m b e r );
S a v e F i l e . W r i t e L i n e ( ( a c c . S a v i n g s + i n p u t 1));
S a v e 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 ));
SaveFile.WriteLine(acc.first_name);
S a v e F i l e . W r i t e L i n e ( a c c .l a s t _ n a m e ) ;
S a v e F i l e .C l ose ();
}

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

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 ( " S a v i n g 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 B a l a n c e : { 0 } " ,
a c c .C h e c k i n g ) ;

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);

Arrays as M em ber Fields


A nother key component to im plem ent w hen dealing w ith a list of classes is the array
reference type. This powerful, yet som ew hat supplem ental, string type is still a very
useful data block, especially when dealing w ith the integral data types. Here, w ell w ant to
exam ine the proper forms w hen working w ith array s both as p a rt of the class and as a
component of its methods. Note also th a t while the array in our example was declared as
a private value, its length is still left as a public reference, and thus will not cause an error
(see Example 5.16).

335
C# and Game Programming

E xam p le 5.16. A rrays as m em b er H elds.


us ing System;

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 ] );
}

sta tic vo i d Main() {


D y n a m i c V a r i a b l e s i n st anc e = new D y n a m i c V a r i a b l e s (10);
for (short i = 0; i < i n s t a n c e .a r r a y .Length; i + +) {
i n s t a n c e .S e t E l e m e n t ( i );
C o n s o l e . W r i t e ("{0} ", i n s t a n c e .R e a d E l e m e n t (i ));}
C o n s o l e .W r i t e L i n e ();

Overloading M em ber Functions


Overloading occurs w henever two or more user-defined functions are referenced using a
single definition. To avoid conflicts, however, definitions m ust differ by at least one passing
argum ent. Logically, if two functions were sim ilar enough to w arran t the same name, and
if th eir argum ents were identical, th en efforts should be tak e n to unify those functions.
H ere I’ve listed two examples, one to dem onstrate how to im plem ent two similar, but
overloaded functions, and the other to dem onstrate how to avoid unnecessary overloads
(see Examples 5.17 and 5.18).

336
Chapter 5: Object-Oriented Design

Exam ple 5.17 Com bining tw o sim ilar overloaded functions.


/* This f unc t i o n just saves the account. */
p u b l i c vo i d S a v e F i l e s ( B a n k A c c o u n t acc) {
S t r e a m W r i t e r S a v e F i l e = new S t r e a m W r i t e r ( @ " C : \ M y F i l e . t x t " );
S a v e F i l e .W r i t e L i n e ( a c c .p i n _ n u m b e r );
S a v e F i l e .W r i t e L i n e ( a c c .a c c o u n t _ n u m b e r );
S a v e F i l e . W r i t e L i n e ( ( a c c .S a v i n g s ) );
S a v e F i l e .W r i t e L i n e ( ( a c c .C h e c k i n g ) );
S a v e F i l e .W r i t e L i n e ( a c c .f i r s t _ n a m e ) ;
S a v e F i l e . W r i t e L i n e ( a c c .l a s t _ n a m e );
S a v e F i l e .C los e ();
}

// This f u n c t i o n alte rs our acc o u n t b a l a n c e s and then saves those


// va lu e s to a d e s i g n a t e d file
p u b l i c v o i d S a v e F i l e s ( B a n k A c c o u n t a c c , short inputl, short input2) {
S t r e a m W r i t e r Sa v e F i l e = n ew S t r e a m W r i t e r (@ " C : \ M y F i l e . t x t ");
S a v e F i l e .W r i t e L i n e ( a c c .p i n _ n u m b e r );
S a v e F i l e . W r i t e L i n e ( a c c .a c c o u n t _ n u m b e r );
S a v e F i l e .W r i t e L i n e ( ( a c c .Sa vin gs + inputl));
S a v e F i l e .W r i t e L i n e ( ( a c c .C h e c k i n g + input2));
S a v e F i l e .W r i t e L i n e ( a c c .f i r s t _ n a m e ) ;
SaveFile.WriteLine(acc.last_name);
S a v e F i l e .C l o s e ();
}

E xam p le 5.18. A v o id in g o v erlo a d s.


p u b l i c v o i d S a v e F i l e s ( B a n k A c c o u n t acc, short inputl, short input2) {
S t r e a m W r i t e r S a v e F i l e = new S t r e a m W r i t e r ( @ " C : \ M y F i l e . t x t " );
S a v e F i l e . W r i t e L i n e ( a c c . p i n _ n u m b e r );
S a v e F i l e . W r i t e L i n e ( a c c .a c c o u n t _ n u m b e r );
S a v e F i l e .W r i t e L i n e ( ( a c c .Sav ing s + inputl));
S a v e F i l e . W r i t e L i n e ( ( a c c .C h e c k i n g + input2));
S a v e F i l e . W r i t e L i n e ( a c c .f i r s t _ n a m e ) ;
S a v e F i l e .W r i t e L i n e ( a c c .l a s t _ n a m e ) ;
S a v e F i l e .C l o s e ();
}

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

p r iv a t e and p r o t e c t e d M em ber Functions


Private and pro t e c t e d m em ber functions (also known as predicate or utility func­
tions) are specialized m em ber functions used only for th a t class’ internal reference. These
functions can be used to read or display data, and are generally used to support the opera­
tions of th a t class’ public m em ber function. P r i v a t e / p r o t e c t e d m em ber functions
are not intended for use by outside references, b u t are generally w ritten w ithout any
specific notation. To convert our previous program into one th at uses private member func­
tions, w e simply need to revise our class’internal definition (see Examples 5.19 and 5.20).

E xam ple 5.19. P riv a te m em b er fu n c tio n s (m eth od s).


usi ng System;
using S y s t e m . 10;

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 ();
}

p r i v a t e v o i d S a v e F i l e ( B a n k A c c o u n t acc, short inputl,


short input2) {

S t r e a m W r i t e r file = ne w S t r e a m W r i t e r (@ " C : \ M y F i l e . t x t ");


f i l e . W r i t e L i n e ( a c c . p i n _ n u m b e r );
f i l e .W r i t e L i n e ( a c c .a c c o u n t _ n u m b e r );
f i l e .W r i t e L i n e ( ( a c c .saving s + inputl));

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 ());

R a n d o m rnd = new R a n d o m ();


a c c .a c c o u n t _ n u m b e r = rnd.Next(l, 100);

C o n s o l e . W r i t e L i n e ("\nYour Ne w A c c o u n t N u m b e r is: {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 ("\nEnter your first name: ");
a c c .f i r s t _ n a m 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 ("\nEnter yo ur last name: ");
a c c .la s t _ n a m e = C o n s o l e .R e a d L i n e ();
Co n s o l e .W r i t e L i n e ("\nEnter Your Savi ngs Balance: 11) ;
ac c . s a v i n g s = d e c i m a l .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 L i n e ("\nEnter Your C h e c k i n g Balance: ") ;
a c c . c h e c k i n g = d e c i m a l .P a r s e ( C o n s o l e .R e a d L i n e ());

Save Fil e(a cc, 0, 0) ;


}

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 ());

i f ( C h a r .ToU ppe r(i npu t) == ’C 1) {


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 oUp per (in put ) == fV') {
a c c o u n t .V i e w F i l e ( a c c o u n t );
} else {
break;

account.ViewFile(account);

E xam ple 5.20. P r o te c te d m em b er fu n c tio n s (m eth od s).


p r o t e c t e d v o i d R e a d F i l e s ( 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 R e a d F i l e = n ew S t r e a m R e a d e r (@ " 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 ( 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 ast _ 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 .Close ();
}

p r o t e c t e d v o i d S a v e F i l e s ( B a n k A c c o u n t acc, short inputl, short input2) {


S t r e a m W r i t e r S a v e F i l e = ne w S t r e a m W r i t e r (@ " C : \ M y F i l e . t x t ");
S a v e F i l e .W r i t e L i n e ( a c c .p i n _ n u m b e r );
S a v e F i l e .W r i t e L i n e ( a c c .a c c o u n t _ n u m b e r );
S a v e F i l e .W r i t e L i n e ( ( a c c .Sa vin gs + inputl));
S a v e 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 ) );
SaveFile.WriteLine(acc.first_name);
S a v e F i l e .W r i t e L i n e ( a c c .l a s t _ n a m e ) ;
S a v e F i l e .Close ();
}
Constructors

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).

Each declared instance is allocated a portion of system memory (commonly


referred to as the heap). In native C++ it is also important to define the
restoration of that memory (normally referenced by that classes destructor—
see this chapter’s section on destructors).1

E xam p le 5.21. C on stru ctors.


u si ng System;
using S y s t e m . 10;

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).

E xam p le 5.22. O v erlo a d in g c o n str u c to r s.


usi ng System;
using S y s t e m . 10;

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.

E xam p le 5.23. M em b erw ise cop y—a s s ig n in g in sta n c e s.


usi n g System;
using S y s t e m . 10;

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;
}

public BankAccount(decimal IRate) {


InterestRate = .03M;
LoanRate = .13M;
}

public BankAccount(decimal IRate, de c i m a l LoanRate) {


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;

Reading and W riting to Private Mem bers


Encapsulation is a key point when working with private members, but for varying reasons
we often find th a t we need to gain a t least lim ited access in order to im plem ent changes
w ithin our programs. These changes can be facilitated with the use of specialized m ember
functions. Practically, these functions are usually broken up into two forms: the first to
read (compare, get) those values, and the second to set (put, write) or alte r those values.
Typically, the setting functions are void, while the reading functions are m eant to retu rn
the implied value. Both are usually only used to access one class member, but several
equivalent m em ber functions may be w ritten to include as m any m em bers as required
(see Example 5.24).

E xam p le 5.24. R ea d in g and w r itin g to p r iv a te m em b ers.


p u b l i c d ecim al R e a d l n t e r e s t R a t e () {
return(InterestRate);
}

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.

E xam p le 5.25. The th is re fe r en ce .


/* W r i t t e n w i t h the this reference. */
usin g System;
using S y s t e m . 10;

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 ());

R a n d o m rnd = new R a n d o m ();


t h i s .a c c o u n t _ n u m b e r = r n d . N e x t (1, 100);
C o n s o l e .W r i t e L i n e ("\nYour N e w A c c o u n t N u m b e r is: {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 ("\nEnter your first name: ");
t h i s .f i r s t _ n a m 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 ("\nEnter your last name: ");
t h i s . l a s t name = C o n s o l e .R e a d L i n e ();

345
C# and Game Programming

C o n s o l e .W r i t e L i n e ("\nEnter Your S avi ngs Balance: " ) ;


t h i s . s a v i n g s = d e c i m a l .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 L i n e ("\nEnter Y our C h e c k i n g Balance: ");
t h i s .c h e c k i n g = d e c i m a l .P a r s e ( C o n s o l e .R e a d L i n e ());
t h i s .S a v e F i l e (0, 0) ;

p r i v a t e voi d S a v e F i l e (short inputl, short input2) {


S t r e a m W r i t e r file = n e w S t r e a m W r i t e r (@ " C : \ M y F i l e . t x t ");
file.WriteLine(this.pin_number);
f i l e . W r i t e L i n e ( t h i s .a c c o u n t _ n u m b e r );
f i l e .W r i t e L i n e ( ( t h i s .sa vin gs + inputl));
f i l e .W r i t e L i n e ( ( t h i s .c h e c k i n g + input2));
f i l e . W r i t e L i n e ( t h i s .f i r s t _ n a m e ) ;
file.WriteLine(this.last_name);
f i l e .Clo se ();
}

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 ());

i f ( C h a r .ToUpp er( inp ut) == 'C') {


a c c o u n t .C r e a t e F i l 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 ();

E xam p le 5.26. T h is as an im p lied k eyw ord .


/* "this" as an i m p l i e d keyword. */
u si n g System;
usin g S y s t e m . 10;

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

C o n s o l e .W r i t e L i n e ("\nYour N ew A c c o u n t N u m b e r is: {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 ("\nEnter your first name: ");
f i r s t _ n a m 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 ("\nEnter your last name: ");
l a s t _ n a m 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 L i n e ("\nEnter Your Sav ing s Balance: ");
savin gs = d e c i m a l .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 L i n e ("\nEnter You r C h e c k i n g Balance: ");
c h e c k i n g = d e c i m a l .P a r s e ( C o n s o l e .R e a d L i n e ());
S a v e F i l e (0, 0) ;

p r i v a t e v o i d S a v e F i l e (short inputl, short input2) {


S t r e a m W r i t e r file = n ew S t r e a m W r i t e r ( @ " C : \ M y F i l e . t x t ");
f i l e .W r i t e L i n e ( p i n _ n u m b e r );
f i l e .W r i t e L i n e ( a c c o u n t _ n u m b e r );
f i l e . W r i t e L i n e ( (savings + inputl));
f i l e .W r i t e L i n e ( (checking + input2));
file.WriteLine(first_name);
file.WriteLine(last_name);
f i l e .C l o s e ();
}

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);

class Cla ssl {


s t at ic v o i d Main() {
B a n k A c c o u n t a cco u n t = n ew B a n k A c c o u n t ();

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).

E xam p le 5.27. O verload ed c o n str u c to r s an d a d estru cto r.


u si ng System;
usi ng S y s t e m . 10;

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 ();
}
}
}

Introducing Operator Overloading


A nother feature available to us through the use of class m anipulations is the ability to
overload operators. Operator overloading is the reapplication of operators to include class
m anipulations. The standard class operator overloads include object-to-object and object-
to-numeric values (including variables). Traditionally, C++ overloaded operators included
stream-insertion ( « ) , stream-extraction ( » ) , and array notation ([ ]), but C# has lim ited
the num ber of operaters th a t can be overloaded (see Table 5.1). The most im portant point

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.

+ - * / %

!=
> < >= <= ==

» « ! ++ —

tru e false i &

T able 5.1. C# o v erlo a d op era to rs.

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.

E xam p le 5.28. In tro d u c in g o p e r a to r o v erlo a d in g .


us ing System;

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;
}

p u b l i c st ati c Ob j e c t s o p e r a t o r + (Objects Ob, int value) {


O b . N u m b e r += value;
return(Ob);
}

p u b l i c s ta tic O b j e c t s o p e r a t o r + (Objects Ob, O b j ect s Ob2) {


O b . N u m b e r += 0b2 .Nu mbe r;
return(Ob);
}

p u b l i c st ati c O bj e c t s o p e r a t o r - ( O b j e c t s Ob, int value) {


O b . N u m b e r -= value;
return(Ob);
}

p u b l i c s ta tic Obj e c t s o p e r a t o r -( O b j e c t s Ob, O bje c t s 0b2) {


O b . N u m b e r -= Ob2 .Nu mbe r;
return(Ob);
}

p u b l i c st atic O bje c t s o p e r a t o r * (Objects Ob, int value) {


O b . N u m b e r *= value;
return(Ob);
}

352
Chapter 5: Object-Oriented Design

p u b l i c stat ic O bje c t s o p e r a t o r * (Objects Ob, Ob j e c t s Ob2) {


O b . N u m b e r *= Ob2 .Nu mbe r;
return(Ob);
}

p u b l i c sta tic O b j e c t s o p e r a t o r /( Ob j e c t s Ob, int value) {


O b . N u m b e r /= value;
return(Ob);
}

p u b l i c st ati c Ob je c t s o p e r a t o r / (Ob j e c t s Ob, Obj e c t s 0b2) {


O b . N u m b e r /= 0b2.N umb er;
return(Ob);
}

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);
}
}
}

Overloading Comparison Operators


Another im portant type of overloading involves the use of the comparison operators. Here,
we’ll w ant to use the Boolean data type with our choice of constants, variables, and object
references. We’ll also need to include m atching comparisons, like greater th a n and less
th an symbols, for each overload (see Example 5.29).

E xam p le 5.29. O v erlo a d in g co m p a riso n op era to rs.


us ing System;

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;
}

pu b l i c sta tic bool o p e r a t o r > ( O b j e c t s One, O bje c t s Two) {


r e t u r n ( O n e .N u m b e r > T w o. Num ber );
}

p u b l i c stat ic bool o p e r a t o r < ( O b j e c t s One, Ob je c t s Two) {


r e t u r n ( O n e .N u m b e r < T wo. Num ber );
}

354
Chapter 5: Object-Oriented Design

p u b l i c stati c b ool o p e r a t o r < ( O b j e c t s One, int Value) {


r e t u r n ( O n e .N u m b e r < Value);
}

pu b l i c sta tic bool o p e r a t o r > ( O b j e c t s One, int Value) {


r e t u r n ( O n e .N u m b e r > Value);
}

p u b l i c s ta tic bo ol o p e r a t o r < = ( O b j e c t s One, O b j e c t s Two) {


r e t u r n ( O n e .N u m b e r <= T wo. Num ber );
}

p u b l i c s ta tic bo ol o p e r a t o r > = ( O b j e c t s One, O b j e c t s Two) {


r e t u r n ( O n e .N u m b e r >= Tw o.N umb er) ;
}

p u b l i c sta tic bo ol o p e r a t o r < = ( O b j e c t s One, int Value) {


r e t u r n ( O n e .N u m b e r <= Value);
}

p u b l i c sta tic bool o p e r a t o r > = ( O b j e c t s One, int Value) {


r e t u r n ( O n e .N u m b e r >= Value);
}

sta tic v o i d Main() {


O b j e c t s C l ass l = new Ob j e c t s (4);
O b j e c t s C l ass 2 = n ew O b j e c t s (2);

// O b j e c t - t o - n u m e r i c v alu e (or variable)


if (Classl > 2)
Console.WriteLine(true);
if (Classl < 2)
C o n s o l e .W r i t e L i n e ( t r u e ) ; // false
if (Classl >= 2)
C o n s o l e .W r i t e L i n e ( t r u e );

// 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

Nesting Overloaded Operators


Another interesting feature th a t we will w ant to exploit is the ability to include overloaded
operators as p a rt of a subclass or nested class. This allows for several distinct m anipula­
tions, which include the ability to reference specific functions and/or specific object refer­
ences from w ithin our m ain class. For example, if we were to w rite the program in Ex­
am ple 5.30 to include two independent classes, we would not be able to reference both
classes’sets of objects interdependently, which would force us to do most of our calculation
externally. This would also require us to revise the nested class’ private m em bers to be
included as public references, which would work against our ultim ate goal of complete
encapsulation (see Example 5.30).

E xam p le 5.30. N e stin g o v e r lo a d e d op era to rs.


u si ng System;

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 A t o m s ( s t r i n g Symbol, int Number, d eci m a l Weight) {


t h i s . S y m b o l = Symbol;
t h i s . N u m b e r = Number;
t h i s . W e i g h t = Weight;
}

p u b l i c s t ati 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 tom s At) {
re tur n (NE.Weight == At .We i g h t ) ;
}

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

Overloading Unary Operators


There are several ra th e r practical m anipulations th a t involve overloading unary opera­
tors. One such example would include the use of the n o t operator. This unary operator
could be used to sim ultaneously access a Boolean component while inverting its stored
value. O ther useful modifiers are the incrementing and decrementing operators, and the
negative notation; inserted in front of a class com ponent’s value , they are often used to
indicate a reverse in direction and/or an implied m athem atical reference (Example 5.31
explores the im plem entation of these concepts).

E xam p le 5.31. O v erlo a d in g u n a ry o p era to rs.


usin g System;

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;
}

p u b l i c sta tic b ool o p e r a t o r ! (Television TV) {


r e t u r n (!T V .P o w e r ) ;
}

pu b l i c sta tic T e l e v i s i o n o p e r a t o r + + ( Television TV) {


T V .C h a n n e l + + ;
return(TV);
}

p u b l i c sta t ic T e l e v i s i o n o p e r a t o r - - (Television TV) {


T V .C h a n n e l - - ;
return(TV);
}

st ati c voi d Main() {


T e l e v i s i o n TV = new T e l e v i s i o n ();
if (!TV)
C o n s o l e .W r i t e ("The TV is not t u r n e d on. \n");

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).

While C++ is still backward compatible with multiply-inherited structures,


C# is not, thus such techniques will not be discussed.

E xam p le 5.32. P u b lic in h e r ita n c e w ith p u b lic m em b ers.


u si ng System;

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

p u b l i c short Width, Length;

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 ) ;

E xam p le 5.33. P u b lic in h e r ita n c e w ith p r o te c te d m em b ers.


u si ng System;

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 ) ;
}
}
}

Inheritance versus Composition


Inheritance and composition describe two sim ilar but distinct types of references. Composi­
tion is formed under a “has a” standard. In other words, a shared class “has a” relationship
with a linking class. In contrast, the base component of an inherited class doesn’t just “have
a” relationship with its derived class, but instead, rather, the derived class “is an” object of
the base class. This relationship transcends the objects in question and speaks to the very
nature of the components. For example, if we were to say th a t we had a horse and carriage,
it would imply th a t the horse was needed to pull th a t carriage. The carriage, then, “has a”
relationship connecting its use with the horse. Yet, if we were to say th a t the carriage was
made out of wood, it would be understood th at the wood “is a” part of the carriage, just as the
base class becomes a p art of the inherited class.

361
C# and Game Programming

Inheriting Constructors and Destructors


As explained in earlier sections, an I is a member function often used to initialize objects as
pertaining to the values presented in th eir declarations, or thereby calculated as p a rt of
th a t class. The initialization is done autom atically (at the m om ent of declaration), w ith
reference to one of possibly several overloading constructor references. Once an inherited
class is introduced, this initialization is compounded w ith the need for both a base class
initialization and an inherited class initialization. Base class constructors, however, are
not inherited by derived classes, and thus do not need to be overloaded or overridden. The
order of derivation with regards to a constructor of an inherited class is always linked from
the base class to the derived class, w ith the reverse order for the destructor ( from the
derived class to the base class).

private versus protected Inheritance


E arlier in this chapter p r i v a t e and p r o t e c t e d m em bers seem ed alm ost interchange­
able. That is, each protected against unauthorized referencing, granting access to only the
properly labeled m em ber functions; they allowed for predicate/utility m em ber func­
tions; and they both seem ed to work well w ith the nested and inherited classes. The
uniqueness of the protected class became evident when attem pting to access a private
m em ber variable from inside an inherited class (review Exam ples 5.33 and 5.34). In
these differing cases, we found th a t the protected modifier acted much more like the
public modifier th an its private counterpart, in th a t it enabled public access to the in h er­
ited class while still enforcing its rule of privacy on the accompanying program . To the
same extent, the protected inherent classes allow for the sharing of data base and derived
classes, but private fields and m ethods do not, thus they require methods to retrieve th a t
data (see Exam ples 5.34 and 5.35).

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 ) ;
}
}
}

E xam p le 5.35. P u b lic in h e r ita n c e w ith p r iv a te m eth o d s and H elds.


us ing System;

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 ) ;
}
}
}

Using Multiply Linked Single-Inheritance


Once an inherited class is developed, it is subject to any renderings of the prior in h er­
ited class. The combined attrib u tes become p a rt of the th ird object, w ith the exception of
the constructor functions and the assignm ent statem ents, since neither of these are passed
to an inheriting class. Again, the level of access granted to the inheriting class is prim arily
based on the security established by th e specified m em bers. Once a secondary inherited

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).

E xam p le 5.36. L in k in g c la sse s.


us i n g System;

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);

Overriding and Virtual Methods


In addition to overloading a function (i.e., changing th e sig n a tu re or p a ra m e te rs of
th a t function), we can also o v e r r i d e a function so as to force th e com piler to accept a
secondary version of th a t function. As its nam e im plies, th e keyw ord o v e r r i d e is
used to override m em bers in h e rite d from a base class. These in h e rite d m ethods
m ust have m atching sig n atu res and be e ith e r virtu al, ab stract, or previously overrid­
den. O verriding also allows us to m an ip u la te a pro g ram ’s d a ta so as to give it the
illusion of consistency or to save th e trouble of revising a previous class. The second­
ary version of th e function is th e obvious choice, as our in stan ce w as declared as
p a rt of th a t in h e rite d class. On a c a u tio n ary note, it should also be m entioned th a t
if any overriding functions also reference th e ir base version (as is comm only done
w ith priv ately in h e rite d classes), th a t function’s reference will be div erted back to
th e in h e rite d function (we can also re tu rn access to the original m ethod via th e base
comm and).

366
Chapter 5: Object-Oriented Design

Follow ing th is sam e line of reasoning, we m ight m istak en ly conclude th a t p ri­


v ately passed in h e rite d classes a re only accessible th ro u g h in te rn a l use as w ith
predicate and/or o ther un ity type functions. However, th is is not the case, since all the
techniques used to access a s ta n d a rd yet p riv ately controlled class are also available
from w ith in th e derived class. Once a need for a p riv ately in h e rite d class is e s ta b ­
lished, th e correct approach is to create a set of m em ber functions th a t relies on in d i­
rect access, th u s c reatin g a relay from th e in h e rite d to base functions, hence th e Set
m ethods.
The keyword v i r t u a l is a m odifier th a t sets a m ethod of a base class so th a t it can
be overridden in a derived class. W hen a v i r t u a l function is referenced it searches for
an overriding m ethod. O verriding, as explained above, forces th e com piler to accept a
secondary version of th a t function as rela te d to a secondary/inherited class. The poly­
m orphic effect is accom plished a t ru n tim e (know n as la te binding) r a th e r th e n a t
com pilation (known as early binding), as w as th e case w ith operator and m em ber style
overloading, v i r t u a l functions are declared using th e sta n d a rd m em ber’s declaration
preceded by th e keyw ord v i r t u a l . N e ith e r co n stru cto rs or frien d functions can be
accessed using th is m ethod, b u t v i r t u a l d estru cto rs are allow ed (see Exam ple 5.37).
In c o n tra st to th e definition of an overloading function, a function th a t is overridden
m u st include an identical list of p a ram eters.

Inherited classes that do not include properly overwritten virtual functions


are then subject to the default virtual functions included in their base classes.
If a multilevel inherited class cannot find a properly declared virtual function,
it may mistakenly revert through each inherited class until an appropriate
function is found.

E xam p le 5.37. L in k in g c la s s e s w ith k ey w o rd s o v errid e and v irtu a l.


us i n g System;

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 ase (A re a X, short a) {


X .B a s e = a ;
}

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 lic s t a t i c v o id S e tH e ig h t(A re a X, short h) {


X.H e ig h t = h ;
}

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 " ) ;
}
}

p u b lic c la s s P a ra lle lo g r a m : A rea {


p u b l i c P a r a l l e l o g r a m ( s h o r t w, s h o r t 1) {
S e tB a s e (th is , w )/
S e tH e ig h t(th is , 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 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

S et Bas e2( thi s, b ) ;


S e t H e i g ht( thi s, 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 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 ();

P a r a l l e l o g r a m Shapel = new P a r a l l e l o g r a m (5, 5);


C a l c u l a t e A r e a ( S h a p e l );

P a r a l l e l o g r a m Shape2 = new P a r a l l e l o g r a m (5, 6);


C a l c u l a t e A r e a ( S h a p e 2 );

T r i a n g l e Sha pe3 = n e w T r i a n g l e (5, 6);


C a l c u l a t e A r e a ( S h a p e 3 );

Ci r c l e Shape4 = new C irc l e (3);


C a l c u l a t e A r e a ( S h a p e 4 );

T r a p e z o i d Shap e5 = n e w Trap ezo id( 4, 5, 6);


C a l c u l a t e A r e a ( S h a p e 5 );

Inherited v i r t u a l functions are considered virtu al by default, th u s the use of the


keyword v irtual is considered optional and is generally only restated for program clarity.
Therefore, application of a v i r t u a l function should include some type of generalized re ­
trieving notation.

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.

Individual properties declared with an abstract modifier reference cannot also


contain a static modifier (see Example 5.38).

371
C# and Game Programming

E xam p le 5.38. A b stra ct b ase cla ss.


us i n g System;

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;
}

pu b l i c sta tic short R e a d B a s e ( A r e a X) {


r e t u r n ( X .B a s e ) ;
}

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;
}

pu b l i c sta tic v o i d S e t B a s e 2 ( A r e a X, short b) {


X .Base2 = b;
}

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 );
}
}

p u b lic c l a s s P a r a lle lo g r a m : A rea {


p u b l i c P a r a l l e l o g r a m ( s h o r t w, s h o r t 1) {
S e tB a s e (th is , w );
S e tH e ig h t(th is , 1 );
}

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

Exam ple 5.40. G eneral catch.


u si ng System;

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 !");

E xam p le 5.41. S p e c ific catch .


us i n g System;

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

Nested try Blocks


T ry block structures can be nested to protect against a host of errors and/or deliberately
flawed user inputs (see Example 5.42).

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.

E xam p le 5.42. N e sted t r y b lock s.


/* N e s t e d t r y - b l o c k s */
u sing System;

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;

C o n s o l e .W r i t e L i n e (" L e t 1s d ivi de some n u m b e r s. .." );

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).

E xam p le 5.43. C larifyin g e x c e p tio n s—th e k ey w o rd th row .


u si ng System;

namespace Chapter5 {
p u b l i c class Er rors {
sta tic vo i d Main() {
s tr ing Input;
int X, Y;

C o n s o l e .W r i t e L i n e (" L e t 1s di v i d e some n u m b e r s.. .") ;

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!");
}

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: ");


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)) {
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 " ) ;
}
}
}
}
}

User-Defined Exception Classes


Occasionally, we’ll w ant to define our own exception classes. These are special case excep­
tions th a t may require additional information and/or input. An exception class is an inher­
ited class th a t is derived (either directly or indirectly) from a key base class (nam ely
System.ApplicationException). In all other respects, an exception class mimics the rules
of a standard inherited class (see Example 5.44).

380
Chapter 5: Object-Oriented Design

Example 5.44. U ser-defined exceptions.


usi ng System;

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;

C o n s o l e .W r i t e L i n e (" L e t 1s d i v i d e some n u m b e r s. .." );

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 !") ;
}

C o n s o l e .W r i t e ("Enter y our d e n o m i n 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 .IsNum ber (In put , 0)) {


Y = i n t .P a r s e (I n p u t ) ;
} else {
t h r o w ne w 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 In te g e r V a l u e was Exc e p t e d ! " ) ; }

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

C o n s o l e .W r i t e ("Please e n ter a n ew 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 ) ;
} 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)

E xam p le 5.45a. N e sted e x c e p tio n s.


n a m e s p a c e Ch a p t e r 5 {
class M a t h e m a t i c s {
p u b l i c static v o i d D i v i s i o n ( r e f int X, ref int Y) {
if (X == 0 && Y == 0) {
X = Y = 1;
t hr ow n e w E x c e p t i o n (" Z e r o B y Z e r o E x c e p t i o n " );
} else
Console.WriteLine(X/Y);
}

p u b l i c sta tic v o i d Main() {


stri ng Input;
int X, Y;

C o n s o l e .W r i t e L i n e (" L e t 1s di v i d e some n u m b ers ... ");

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 ) ;

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: ");


Input = C o n s o l e .R e a d L i n e ();
Y = 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");
}
}

E xam p le 5.45b. A p p lied e x c e p tio n s.


n a m e s p a c e Ch a p t e r 5 {
cl ass M a t h e m a t i c s {
p u b l i c s tatic v o i d D i v i s i o n ( r e f int X, ref int Y) {
if (X == 0 & & Y == 0) {
X = Y = 1;
th r o w new E x c e p t i o n ("Z e r o B y Z e r o E x c e p t i o n " );
} else
C o n s o l e .W r i t e L i n e ( X / Y ) ;
}

pu b l i c static v o i d Main() {
st rin g Input;
int X, Y;

C o n s o l e . W r i t e L i n e (" L e t 1s d i v i d e some nu mb e r s . . . " ) ;

wh i l e (true) {

383
C# and Game Programming

C o n s o l e .W r t i 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 ();

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;
}

C o n s o l e .W r i t e L i n e ("Enter your d e n o m i n a t o r now: ");


Input = C o n s o l e .R e a d L i n e ();

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");

}
}
}
}

The Binary Operator as


The binary operator as allows for conversion of an expression to a data type. This operator
is considered a more elegant d ata type, since its expressions can retu rn null data and do
not call exceptions. A s expressions also require reference types and are used to express a

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.

E xam p le 5.46. The b in a ry o p era to r a s.


u s i n g System;

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

E xam ple 5.47. A sim p le d eleg a te.


usin g System;

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).

E xam p le 5.48. E v en ts.


using S y s t e m .C o l l e c t i o n s ;

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).

E xam p le 5.49. Im p le m en tin g p r e p r o c esso r d ir e c tiv e s.


#define De bugTest
#define R e l e a seT est

#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.

#line The line directive is used to alter output that is


caught by warning and error messages. You’ll need
, to include the line number and file name as in
#line 12 wchapter5.cs.”

#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.

T able 5.2. D e fin itio n s o f p r e p r o c esso r d ir e c tiv e s.

The external Modifier


The external modifier (ex te rn ), as its name implies, indicates th at the method will be imple­
m ented externally, such as with the Dlllmport attribute. The external method will contain
all appropriate declarations, but because it is executed outside of our programs, its declaration
does not require a function body. External references do require a term inating semicolon, and
they cannot be used to modify abstract classes. We can also declare our methods using external
modifiers, but these methods will not include implementation, thus, their definitions will
contain no bodies (these methods will also require a term inating semicolon). C++ users will
find this version of extern a bit more constrictive (see Example 5.50).

E xam p le 5.50. The e x te r n m od ifier.


usin g System;
using S y s t e m .R u n t i m e .I n t e r o p S e r v i c e s ;
n a m e s p a c e Ch ap t e r 5 {

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).

E xam p le 5.51. The e x p lic it op erator.


usi n g System;

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 ) ;
}

p u b l i c sta tic vo i d Main() {


int Inte ger = 3;
IsByte Byte = (I s B y t e ) I n t e g e r ;
}
}
}

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).

E xam p le 5.52. The i m p l i c i t op erator.


using System;

namespace Chapter5 {
class IsByte {
byte value;

public IsByte(byte value) {


this.value = value;
}

public static implicit operator byte(IsByte Byte) {


return Byte.value;
}

public static void Main() {


IsByte Byte = new I s B y t e (3);

byte Byte2 = Byte;


}
}
}

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).

E xam p le 5.53. F ix ed p o in ters.


using System;

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 ();

Console.Write("Enter a number: ") ;


T e s tF ix ed .variable = i n t .Parse(Console.R e a d L i n e ());

fixed (int* pointer = & TestFixed.vari ab le ) {


Console.WriteLine("\n{0}", TestFixed.variable);
C o n s o l e .W r i t e L i n e ("\ n {0}", *pointer);
}

The g e t and s e t Accessors


T h e g e t a n d s e t accesso rs a r e n ’t officially keyw ords, ra th e r, th e y a re p a ra m e te rle s s m e th ­
ods n a m e d to m a tc h c e rta in fields, a n d a re u se d in classes a n d in te rfa c e s t h a t hold a body of
e x e c u ta b le d a ta p e r ta in in g to th e sto ra g e a n d re trie v a l of th o se fields. T h e ir e x e c u ta b le
s ta te m e n ts m a y in c lu d e c a lc u la tio n s, con v ersio n s, a n d a la rg e h o s t of o th e r ta s k s , b u t
th e ir u n d e rly in g p u rp o se m u s t inclu d e re a d in g or reco rd in g th o se p ro p e rtie s. T h e body of a n
accesso r is co n sid e re d e q u iv a le n t to a m eth o d , a lth o u g h th e y do n o t in c lu d e id e n tity s ig n a ­
tu re s . T h e g e t accesso r r e tu r n s a v a lu e a n d m ay b e se t to th ro w a v a lu e w h e n need ed ; in
c o n tra s t, th e s e t ac c e sso r is a lw a y s se t to void. T h e k ey w o rd v a l u e is also u se d a s a n
im p lic it p a r a m e te r w h e n s e ttin g o u r fields. T h u s, v a l u e ta k e s on th e v a lu e of a n y p a s s e d
v a ria b le s . T h e g e t a n d th e s e t accesso rs a lw a y s s h a re th e sa m e u se r-d e fin e d n a m e , th u s
th e y c a n n o t e x ist in th e sa m e b a se class. I t is th e re fo re c o n sid e re d n a tu r a l to p lace th e s e t

391
C# and Game Programming

accesso r in th e b a s e class, a n d th e g e t accessor in th e n e s te d d eriv e d class. I t is also im p o r­


t a n t to re m e m b e r t h a t th e v a lu e r e trie v e d by th e g e t p ro p e rty is for re fe re n c e only, w h ile
th e v a lu e re c o rd e d in t h e s e t p ro p e rty is w rite only (see E x a m p le 5.54).

E xam p le 5.54. The g e t and s e t a c c e sso r s—lin k in g c la sse s.


using System;

namespace Chapter5 {
public class BaseClass {
public short width, length;

protected BaseClass () {}

protected B a s e C l a s s (short w, short 1) {


Width = w;
Length = 1;
}

public short Width {


set {
width = value;

public short Length {


set {
length = value;

public class DerivedClass : BaseClass {


protected D e r i v e dC la ss () {}

protected D e r i ve dC la ss (short w, short 1) {


width = w;
length = 1;
}

public new short Width {


get {
return(width);
}

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

in te rfa c e s , in c lu d in g th e p ro te c te d in te r n a l m odifier. In te rfa c e s also follow th e sa m e ru le s


of n a m in g u s e d b y c la sse s, m e th o d s, a n d sim p le v a ria b le s . O nce a n in te rfa c e is in p la c e it
c a n also b e in h e rite d , in c lu d in g m u ltip le in h e rita n c e s , w h ic h is n o t fo rm a lly allo w ed w ith
C# classes.

An interface-class reference also requires that the base class be referenced


first (see Example 5.55).

E xam p le 5.55. In tro d u c in g in te r fa ce s.


using System;

namespace Chapter5 {
interface Baselnterface {
short Width {get; set;}
short Length {get; set;}
}

public class BaseClass : Baselnterface {


private short BIWidth;
private short BILength;

protected BaseClass () {}

protected BaseClass(short Width, short y) {


BIWidth = Width;
BILength = y;
}

public short Width {


get {return(BIWidth);}
set {BIWidth = value;}
}

public short Length {


get {return(BILength);}
set {BILength = value;}
}

protected static short ReadWidth(BaseClass X) {


return (X.Width);

394
Chapter 5: Object-Oriented Design

protected static short ReadLength(BaseClass X) {


return(X.Length);
}
}

public class DerivedClass : BaseClass {


protected DerivedClass () {}

protected DerivedClass(short w, short 1) {


Width = w;
Length = 1;
}

protected static void DisplayArea(DerivedClass Y) {


Console.WriteLine("Area = " + Y.Width * Y.Length);
}
}

public class DerivedX : DerivedClass {


protected DerivedX(short w, short 1) {
Width = w;
Length = 1;
}

protected static void DisplayArea(DerivedX Z) {


Console.WriteLine("Area = " + Z.Width * Z.Length);
}

protected static void Triangle(DerivedX Z) {


Console.WriteLine("The Area of the Triangle is " + .5 *
Z.Width * Z.Length);
}

public static void Main() {


DerivedX Instance = new DerivedX(5, 6);
Console.WriteLine(ReadWidth(Instance));
Console.WriteLine(ReadLength(Instance) ) ;
DisplayArea(Instance);
Triangle(Instance);
}
}
}

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 ).

A compile-time warning will also be issued if the expression is always shown to


be either true or false, and the i s operator cannot be overloaded (see Example
5.56).

E xam p le 5.56. The i s op erator.


u si ng System;

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 " );}
}

p u b l i c sta tic v o i d Main() {


T e s t C l a s s TC = new T e s t C l a s s ();
Test(TC);

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)

E xam p le 5.57. T he k ey w o rd lock .


using System;
using System.Threading;

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);
}

static protected T h r e a d [] test = new T h r e a d [2];

public static void Main() {


MyName FirstName = new M y N a m e ("Salvatore");

397
C# and Game Programming

MyName LastName = new M y N a m e ("Buono");


Thread first = new Thread(new
ThreadStart(FirstName.YourName));
test [0] = first;
test [0] .Start ();

Thread last = new Thread(new ThreadStart(LastName.Y ourName));


test[l] = last;
test [1] .Start ();

The Keyword params


T h e k e y w o rd p a r a m s , w h ic h is s h o r t fo r p a r a m e te rs , is a u s e fu l w a y to p a s s a n a r r a y o f
a n y object ty p e w ith o u t th e in h e r e n t r e q u ir e m e n t of e x p lic itly d e c la rin g t h a t th e d a ta
ty p e be d e c la re d a s a n a rra y . N o a d d itio n a l p a r a m e te rs m a y follow th e d efin itio n , a n d only
one object m a y b e 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 . T h is m e th o d is u se fu l w h e n d e c la r­
in g a n a r g u m e n t w h e re th e n u m b e r o f a r g u m e n ts is u n k n o w n . I t is a lso im p o r ta n t to
re m e m b e r to in c lu d e r e a d a n d /o r o u t c o m m a n d s to a v o id lo sin g d a ta c h a n g e s (see E x ­
a m p le 5.58).

E xam p le 5.58. The k ey w o rd param s.


using System;

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 ) ;
}

public static void Main() {


P a r a m s ("Salvatore ", "A. ", "Buono\n");
}

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

The Keyword stackalloc


T h e k e y w o rd s t a c k a l l o c , w h ic h is s h o rt for stack allocating, is u s e d to a llo c a te blocks of
m e m o ry re fe re n c e d fro m a s ta c k (th is s h o u ld n o t be co n fu sed w ith th e h e a p a s e x p la in e d
p re v io u sly ). T h e a d d r e s s e s o f th e s e b lo ck s a r e fix e d /p in n e d , so th e y a r e n o t s u b je c t to
ra n d o m g a rb a g e collection, th e i r te r m in a tio n lin k e d only to th e co m p letio n of th o se m e th ­
ods. A s ta c k a llo c a tin g re fe re n c e is w r itte n to in c lu d e th r e e k e y te rm s : unmanaged type,
th e pointer name, a n d th e integral expression (see E x a m p le 5.60).

E xam p le 5.60. The k ey w o rd s t a c k a l l o c .


using System;

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;

for (int i = 0; i < 3; i++)


Console.WriteLine(pointerl[i]);
}
}
}

M etafiles Defined

M e ta file s a re d efin ed a s a collection of g ra p h ic fu n c tio n s w ritte n in th e form of a b in a ry


re c o rd . G ra p h ic fu n c tio n s in c lu d e lin e s, c u rv e s, a n d a re a s , a s w e ll a s te x t. M e ta file s i n ­
clu d e sp ecificatio n s for c o o rd in a te s, b ru s h e s , p e n s, a n d e m b ed d ed b itm a p s. M e ta file s h a v e
th e a d v a n ta g e of sc a la b ility w ith o u t d e g ra d a tio n , re q u ire le ss m em ory, a n d h a v e a g r e a te r
d e g re e of d ev ice in d e p e n d e n c e . M e ta file s c a n a lso be c o n v e rte d in to b itm a p s , w h ic h c a n
g r e a tly re d u c e r e n d e r in g tim e , th o u g h t h is w ill c a u s e a lo ss in re s o lu tio n . F ile s s a v e d a s
m e ta file s a r e c a lle d DrawStrings a n d a r e re fe re n c e d w ith th e file e x te n s io n s . e m f (E n ­
h a n c e d M e ta file s) a n d . w m f (W indow s M e ta file s). M e ta file s a r e accessed u s in g th e s t a n ­
d a r d fo rm a t, e.g., Im a g e P l a y e r L = I m a g e . F r o m F i l e (" . . \ \ . . W P l a y e r l . e m f ") ;
a n d Im a g e P l a y e r R = Im a g e . F r o m F ile ( " . . \ \ . . \ \ P l a y e r 2 . w m f" ) ; .

400
Chapter 5: Object-Oriented Design

Building Game Classes


A s w ith p re v io u s g a m e s, o u r n e x t tw o a lso re ly o n a s e t of c la sse s, t h e ir in s ta n c e s , a n d a
h o s t of m e th o d s t h a t m a n ip u la te d a ta to pro d u ce w h a t w e see a s o u r cyber c rea tio n s. T h ese
i n s ta n c e s a n d t h e ir c o m p o n e n ts w e re c o n s tru c te d u s in g th e k n o w led g e b a s e g a th e r e d in
t h is c h a p te r, it is th e re fo re p r u d e n t to d isc u ss th e s e te c h n iq u e s h e re . T h e f ir s t c la ss t h a t
w e l l d is c u s s is a k e y c o m p o n e n t in a ll th e g a m e s; it w a s u s e d to c re a te th e c h a ra c te r s ,
t h e i r w e a p o n s, a n d n e a r ly a ll of th e o b jects t h a t a p p e a re d on th e scre en .

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 ).

E xam p le 5.61. A n im a te d lm a g e.e s


/* Animatedlmage.es: Contains the Animatedlmage class, which is a
* generic class capable of holding and doing animation logic for
* an image. You can sub-class this object to customize its behavior.
*/

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

public const int NORTHWEST = 7;


public const int WEST = 8;

// 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

public int imageOffsetX; // facilitates "relative" positioning


public int imageOffsetY; // by placing image at a specified
// offset to PosX, PosY.

public int animationStep; // How much the image should move/step

public Rectangle constraintBox; // Our sandbox to play in


public int direction; // current direction the image is heading
public bool isActive; // whether the image should be animated
public Animatedlmage owner; // if it's controlled by another image

#region Constructors
public Animatedlmage () : t h i s (0,0) {} // default constructor

public A n i m a t e d l m a g e (int posX, int posY) {


imagePosX = posX;
imagePosY = posY;
isActive = false;
animationStep = DEFAULTSTEP;
}
#endregion

Remember, C# class references a re n ’t p a rt of the m ain program , so they do not


require a m ain m ethod. Also, it’s im p o rtan t to note th a t th e class is left open-
ended, so as to include our m ethods, which are discussed over th e next few
sections.

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.

E xam p le 5.62. A n im ate o b jects

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

T h e s ta n d a r d im a g e d is p la y is sim p le , h a v in g j u s t th r e e ste p s: 1) a G ra p h ic s d e c la ra tio n ,


fo r w h ic h w e l l u s e th e l e t t e r g ; 2) th e m e th o d D r a w lm a g e , w h ic h is in c lu d e d in th e
d ra w in g C la s s a c c e sse d th r o u g h g , a s in g . D r a w l m a g e ; a n d 3) th e s ig n a tu r e s fo r th e
D r a w lm a g e re fe re n c e , e.g., th e c h a r a c te r ’s a c tu a l im a g e , a n x -c o o rd in a te , a y -c o o rd in a te ,
its w id th , a n d its h e ig h t. N o te t h a t th e v a r ia b le s lis te d a r e a c tu a lly th e fie ld s d e c la re d a t
th e to p p a r t o f th e c la ss (see A n im a te d lm a g e .e s o n th e C D -R O M a n d E x a m p le 3 .46 in
C h a p te r 3).

Rescaling Images

A s se e n in th e la s t section, th e h e ig h ts a n d th e w id th s of o u r im a g e s p la y a n im p o rta n t role


in t h e ir d isp lay . T h e h e ig h t a n d w id th , th e n , c a n b e r e s e t, in c re a s e d , o r d e c re a s e d a s
n e e d e d u s in g t h e m e th o d R e s c a le a ls o lo c a te d in th e file A n im a te d lm a g e .e s (see
A n im a te d lm a g e .e s on th e C D -R O M a n d E x a m p le 3.47 in C h a p te r 3).

404
Chapter 5: Object-Oriented Design

Adding Substance to Characters


F o r th e m o st p a r t, c h a r a c te r s a r e j u s t illu s io n s — t h e ir im a g e s d o n ’t h a v e a n y r e a l s u b ­
s ta n c e . T h e re fo re , n a t u r a l lim ita tio n s , d e flectio n s, a n d e v e n co llisio n s w ill a ll go u n n o ­
tic e d b y th e c o m p u te r, u n le s s , of c o u rse, w e w rite a h o s t of m e th o d s t h a t d e fin e th o s e
re s p o n s e s . A ll o f th e s e a r e re la tiv e ly s im p le a n d u s u a lly o n ly in v o lv e re c o rd in g a few key
p o in ts a n d r e v e r s in g o r d is a b lin g th e c h a r a c te r w h e n h e s tu m b le s o n to th o s e p o in ts (see
E x a m p le s 5 .6 5 -5 .6 8 ).

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);
}

H e re w e ’ll n e e d to d e te r m in e if th e re c ta n g le (or w all) in te r s e c ts w ith o u r c h a ra c te r.


T h is is d o n e th r o u g h c a re fu l c o m p a riso n s of e a c h c o o rd in a te in c lu d in g th e im a g e ’s h e ig h t
a n d w id th . I t s h o u ld b e n o te d t h a t th is m e th o d is o v e rlo a d e d w ith one c o m p a riso n m a d e
u s in g a c tu a l p o in ts a n d a n o th e r u s in g th e im a g e .

E xam p le 5.64. I n te r se c ts.

C o llisio n d e te c tio n is a n o th e r k e y p o in t so com m on to g a m es, th u s i t ’s only logical to p lace


i t in s id e o u r c la ss.

// Determines if the given rectangle intersects this image


virtual public bool I nt er se ct s(int x, int y,
int width, int height) {
// simple variable renaming
int x2 = x + width, y2 = y + height, _x = imagePosX;
int _y = imagePosY, _x2 = imagePosX + imageWidth;
int _y2 = 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 ) ) /
}

virtual public bool Intersects(Animatedlmage img) {


return I nt er se ct s(i m g .imagePosX, i m g .imagePosY,
i m g .imageWidth, i m g .imageHeight);
} ___________________________________________________________

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 .

E xam p le 5.65. C on strain T oB ox.

// Moves the image to be within the specified boundary.


// Returns whether any position changes were made,
virtual public bool C o n s t r a in To Bo x() {
bool retVal = false;

if (!isActive)
return false;

if (imagePosX < co ns tr aintBox.X) {


imagePosX = c on straintBox.X;
retVal = true;
} else if ((imagePosX + imageWidth) >
(constraintBox.X + co nstraintBox.W i d t h ) ) {

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;
}

A s w ith C o n s t r a i n T o B o x , D e f l e c t lim its o u r c h a r a c te r 's m o v e m e n t. In th is case,


ho w ev er, th e c h a r a c te r ’s d ire c tio n is re v e rse d , fo rcin g o u r p la y e r to m ove in th e o p p o site
d ire c tio n . T h e p la y e r fe e ls b u m p e d b a c k a s h e c o n tin u e s to m a n ip u la te th e c o n tro ls in th e
d ire c tio n h e d e sire s.

E xam p le 5.66. D eflect.


/ / B a s ic d e f le c t io n
/ / R e t u r n s w h e th e r a n y p o s it io n c h a n g e s w e re m ade.
v i r t u a l p u b lic b o o l D e f l e c t ( i n t x , i n t y , i n t w id t h , i n t h e ig h t ) {
i f ( ! is A c t iv e )
re tu rn f a ls e ;

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;
}

// Deflect override -- deflects off of a given Animatedlmage


virtual public bool Deflect(Animatedlmage img) {
return D ef le ct(img.imagePosX, i m g .imagePosY,
i m g .imageWidth, i m g .imageHeight);
}

// Deflect override -- deflects off of default constraint box


virtual public bool D e f l e c t () {
return Deflect(constraintBox.X, c o ns traintBox.Y,
constraintBox.Width, constra i nt Bo x.H ei gh t);
}

408
Chapter 5: Object-Oriented Design

Creating Infinite Space

A n o th e r v is u a l illu sio n o r ty p e of m o tio n th a t w ill be h a n d le d by th e A n im a te d lm a g e c lass


c a n b e th o u g h t of a s r e p e a tin g o r in fin ite space. W ith th e m e th o d W r a p I n B o x , w e c a n te ll
th e c o m p u te r to te le p o r t o u r c h a r a c te r fro m o n e e n d of th e s c re e n to th e n e x t. S in ce th e
c h a r a c te r is n o t d e fle c te d , a s e n s e o f c o n tin u o u s m o v e m e n t is c re a te d . W r a p I n B o x w ill
s till re ly on th e p a r a m e te r s in c lu d e d w ith c o n s t r a i n t B o x . X a n d c o n s t r a i n t B o x . Y .
T h e c h a r a c te r ’s h e ig h t a n d w id th a r e a lso im p o r ta n t to th e s e c a lc u la tio n s a s a fin a l p o si­
tio n of o u r c h a r a c te r is b a s e d on th e c o n s t r a i n t B o x p o sitio n , th e c o n s t r a i n t B o x
m e a s u re , a n d th e im a g e ’s size (see E x a m p le 3.52 in C h a p te r 3).

Other Types of Deflection

In a d d itio n to b a r r ie r s a n d lim ita tio n s , w e c an also c re a te m e th o d s t h a t sim p ly ch a n g e th e


d ire c tio n o f o u r c h a r a c te r s . T h e m e th o d R e v e r s e D i r e c t i o n does j u s t w h a t its n a m e
im p lie s, c h a n g in g n o r th to so u th , etc. (see E x a m p le 5.67). R o t a t e D i r e c t i o n (liste d in
C h a p te r 3) a llo w s u s to r e a d th e c u r r e n t d ire c tio n of th e c h a r a c te r a n d a d ju s ts it u s in g a
n u m b e r in g s y s te m fro m o n e th r o u g h e ig h t. T h e n u m b e r s on e th r o u g h e ig h t re fle c t th e
b a sic n o rth , n o r th e a s t, e a s t, s o u th e a s t, etc. d ire c tio n s fo u n d in th e o th e r m e th o d s.

E xam p le 5.67. R e v e r seD ir e c tio n .


// Take whatever direction you are going and go the
// opposite direction
virtual public void ReverseD ir ec ti on () {
switch (direction) {
case SOUTHWEST:
direction = NORTHEAST;
break;
case SOUTH:
direction = NORTH;
break;
case SOUTHEAST:
direction = NORTHWEST;
break;

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.

Inheriting from Animatedlmage.es—Player.cs

N ow t h a t w e’ve d e fin e d th e c h a ra c te rs , i t ’s tim e to s t a r t th in k in g a b o u t th e u n iq u e n e s s o f


th e p la y e r. T h e p la y e r, fo r e x a m p le , w ill re q u ir e a life a n d d e a th re fe re n c e . T h e re is th e
o p tio n of a s u p e re g o tra n s fo rm a tio n , a n d ea c h p la y e r sh o u ld h a v e a score to r e p r e s e n t h is
o r h e r w o rk th r o u g h o u t th e g a m e (see E x a m p le 5.68 a n d P la y e r.c s on th e CD -RO M ).

4 10
Chapter 5: Object-Oriented Design

Exam ple 5.68. Player.cs


/* Player.cs: Sub-class of Animatedlmage. Responsible for managing all
* things player-related.
*/
using System;

namespace GameClasses {
public class Player : Animatedlmage {

public int score;


public int deaths;

public Player () : base() {}


public Player(int posX, int posY) : base(posX, posY) {
}
}
}

Inheriting from Player.cs—PlayerlmageArray.es

R e m e m b e r t h a t w h ile C # d oes n o t allo w for m u ltip le in h e rita n c e s , it does allow fo r sin g le


in h e rita n c e in a c h a in o f su b c la sse s. T h u s, P lay erIm a g e A rra y .es c a n in h e r it from P lay er.cs
b o th th e p ro p e rtie s o fP la y e r.c s a n d A n im a te d Im a g e .e s . P la y e rlm a g e A rra y w a s d e sig n e d
fo r u s e w ith a n a r r a y of im a g e s . A m e th o d to lo a d th e im a g e s is re q u ire d , a s w e ll a s
n o ta tio n to in d ic a te th e p o sitio n of th e im ag e (see E x a m p le 5.69 a n d P la y e rIm a g e A rra y .e s
o n th e CD-ROM ).

E xam p le 5.69. P layerIm ageA rray.es

using System;
using System.Drawing;

namespace GameClasses {
public class PlayerlmageArray : Player {
protected Image [] almages;

public Pl ay erlmageArray(int nlmages) : base (0,0) {

411
C# and Game Programming

almages = new Image[nlmages];


}

public void L o a d l m a g e (string fileName, int position) {


if (position >= 0 && a l m a g e s .GetLength (0) < position)
return;

almages[position] = U t i l s .L o a d l m a g e (fileName);
}

// Loads a series of consecutively named images into the array.


// Use "%%" to specify where the index in the filename is.
public void L o a d l m a g e s (string filePattern, int lowerBound,
int upperBound) {
if (lowerBound >=0 && lowerBound < upperBound &&
a l m a g e s .G e t L e n g t h (0) < (upperBound - lowerBound))
return;

for (int i = lowerBound; i <= upperBound; i++)


almages [i] = U t i l s .Loadlmage
(filePattern.Replace("%%", i .T o S t r i n g ()));
}

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.

// overridden member which displays the image with an index ==


// to the heading associated with the image,
override public void Display(Graphics g) {
if (direction >= 0 && direction <= al m a g e s .GetLength (0))
g .Drawlmage(almages[direction], imagePosX, imagePosY,
imageWidth, imageHeight);
}
}
}

4 12
Chapter 5: Object-Oriented Design

Inheriting from Playerlm ageArray.cs-M ultilm agePlayer.es

M u ltiIm a g e P la y e r.e s is th e f ir s t o f tw o c la sse s t h a t in h e r it fro m P la y e rlm a g e A rra y ; th e


seco n d , S h a p e s.c s, w ill b e d e fin e d in t h e n e x t se c tio n . H e re , w e ’re e s s e n tia lly re d e fin in g
th e P la y e rlm a g e A rra y . A n u n iq u e a s p e c t to th is c la ss is t h a t it is n o t p a r t of th e G a m e
C la ss s e t— in s te a d it is in c lu d e d w ith th e R a t R a c e r p ro g ra m (R a t R a c e r is th e la s t g a m e
lis te d in th is c h a p te r). (See E x a m p le 5.70.)

E xam p le 5.70. M u ltiIm a g eP la y er.es

// Inherits from PlayerlmageArray because that has most of


// the functionality we need. We need to override its
// D i s p l a y () method so we can implement the chomping action,
using System;
using Sys te m.Drawing;

using GameClasses;

namespace Games {
public class MultilmagePlayer : PlayerlmageArray {
public bool isChomping;

public MultilmagePlayer(int nlmages) : ba se(nlmages) {


isChomping = false;
}

new public void Display(Graphics g) {


int index;

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;

if (index >= 0 && index < a l m a g e s .GetLength (0))


g .D ra wl mage(almages[index], imagePosX, imagePosY,

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;

Inheriting from PlayerlmageArray.es—Shapes.cs

A n o p tio n t h a t w e ’ve b e e n p la y in g w ith sin ce th e b e g in n in g w a s th e id e a of re n d e r e d


g ra p h ic s . H e re , w e u s e d th e G D I+ to o ls to c re a te a lte r n a te v e rs io n s of o u r c h a ra c te rs . In
a d d itio n , w h ile it w a s p o ssib le to b u ild th e s e c h a ra c te rs fro m o u r b a se coding, w e o p te d to
d ev elo p a n in h e r itin g c la ss to allo w fo r re u s e . T h e co d in g lis te d in th is c la ss is a c tu a lly
d is c u ss e d in b o th C h a p te r s 3 a n d 4; th e r e m a in d e r is lis te d below (see E x a m p le 5.71 a n d
S h a p e s.c s o n th e CD -RO M ).

E xam p le 5.71. P la y erlm a g eA rra y .


using System;
using Syste m.Drawing;
using System.Drawing.Drawing2D;

namespace GameClasses {
public class Shapes : PlayerlmageArray {
public Shapes(int n) : base(0) {}

public Shapes(int posX, int posY) : base(0) {


imagePosX = posX;
imagePosY = posY;
isActive = false;
animationStep = DEFAULTSTEP;
}

414
Chapter 5: Object-Oriented Design

T h e s ta r tin g A ngle d e fin e s th e p o sitio n of o u r sp a c e c ra ft u s e d in C h a p te r 3. In C h a p te r


4 w e u s e a c o n s ta n t a n g le .

// defines the starting angle of a Pie for any given vector


public int s t a r t A n g l e O {
sw it ch(this.direction) {
case 1: r e t u r n (290); // southwest
case 2: return (250); // south
case 3: return(200); // southeast
case 4: r e t u r n (155); // east
case 5: return (105); // northeast
case 6: return(65); // north
case 7: return (25); // northwest
case 8: return (-25); // west
}
return(O); // default northwest
}

T h e a lie n s h e r e a r e r e p r e s e n te d in C h a p te r 4’s B a ttle W ave, a s w e ll a s in G ro u n d


A s s a u lt, w h ic h is lis te d l a t e r in th is c h a p te r.
// complex shape - reusable as a single item
public void AlienO(Graphics g, Brush bAlienColor) {
Point [] Alien = {
new Point (t hi s.imagePosX-10, t h i s .imagePosY-10),
new Point( th is .imagePosX-5, t h i s .imagePosY-10),
new P oi nt(this.imagePosX-5, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY-5),
new Point (t hi s.imagePosX+5, t h i s .imagePosY-10),
new Point( th is .imagePosX+10, t h i s .imagePosY-10),
new P oi nt(this.imagePosX+10, t h i s .imagePosY-5),
new Po int(this.imagePosX+5, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY+5),
new Point( th is .imagePosX+10, t h i s .imagePosY+5),
new Point (t hi s.imagePosX+10, t h i s .imagePosY+10),
new Point( th is .imagePosX-10, t h i s .imagePosY+10),
new Po int(this.imagePosX-10, t h i s .imagePosY+5),
new Point( th is .imagePosX-5, t h i s .imagePosY+5),
new P oi nt(this.imagePosX-5, t h i s .imagePosY-5),
new Point( th is .imagePosX-10, t h i s .imagePosY-5),
new Point( th is .imagePosX-10, t h i s .imagePosY-10)};

g .FillPolygon(bAlienColor, A l i e n ) ;
}

415
C# and Game Programming

// complex shape - reusable as a single item


public void Alienl(Graphics g, Brush bAlienColor) {
P o i n t [] Alien = {
new Point (t hi s.imagePosX-10, t h i s .imagePosY-10),
new Point( th is .imagePosX-5, t h i s .imagePosY-10),
new Point( th is .imagePosX-5, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY-5),
new Poin t(t hi s.imagePosX+5, t h i s .imagePosY-10),
new Point (t hi s.imagePosX+10, t h i s .imagePosY-10),
new Poin t( th is.imagePosX+10, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY-5),
new Point (t hi s.imagePosX+5, t h i s .imagePosY+5),
new Point (t hi s.imagePosX+10, t h i s .imagePosY+5),
new Point (t hi s.imagePosX+10, t h i s .imagePosY+10),
new Poin t( th is.imagePosX+5, t h i s .imagePosY+10),
new Point( th is .imagePosX+5, t h i s .imagePosY+5),
new Point( th is .imagePosX-5, t h i s .imagePosY+5),
new Po in t( th is .imagePosX-5, t h i s .imagePosY+10),
new Po in t(this.imagePosX-10, t h i s .imagePosY+10),
new Poin t( th is .imagePosX-10, t h i s .imagePosY+5),
new P oi nt(this.imagePosX-5, t h i s .imagePosY+5),
new Point (t hi s.imagePosX-5, t h i s .imagePosY-5),
new Poin t( th is .imagePosX-10, t h i s .imagePosY-5),
new Point( th is .imagePosX-10, t h i s .imagePosY-10)};

g .FillPolygon(bAlienColor, A l i e n ) ;
}

// complex shape - reusable as a single item


public void Alien2(Graphics g, Brush bAlienColor) {
P o i n t [] Alien = {
new Poin t( th is .imagePosX-5, t h i s .imagePosY-10),
new Point( th is .imagePosX+5, t h i s .imagePosY-10),
new Point( th is .imagePosX+5, t h i s .imagePosY-5),
new Poin t( thi s.imagePosX+10, t h i s .imagePosY-5),
new Point (t his .imagePosX+10, t h i s .imagePosY+10),
new Point( th is .imagePosX+5, t h i s .imagePosY+10),
new Point (t hi s.imagePosX+5, t h i s .imagePosY),
new Point( th is .imagePosX-5, t h i s .imagePosY),
new Point (t hi s.imagePosX-5, t h i s .imagePosY+10),
new Po in t(this.imagePosX-10, t h i s .imagePosY+10),
new Po in t( th is .imagePosX-10, t h i s .imagePosY-5),
new Point( th is .imagePosX-5, t h i s .imagePosY-5),
new Point (t hi s.imagePosX-5, t h i s .imagePosY-10)};

416
Chapter 5: Object-Oriented Design

g .FillPolygon(bAlienColor, A l i e n ) ;
}

// complex shape - reusable as a single item


public void Alien3(Graphics g, Brush bAlienColor) {
Point [] Alien = {
new P oint(this.imagePosX-10, t h i s .imagePosY-10),
new Po int(this.imagePosX+10, t h i s .imagePosY-10),
new P oi nt(this.imagePosX+10, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY+5),
new P o i n t (t h i s .imagePosX+10, t h i s .imagePosY+5),
new Point( th is .imagePosX+10, t h i s .imagePosY+10),
new Point (t hi s.imagePosX+5, t h i s .imagePosY+10),
new Point ( thi s.imagePosX+5, t h i s .imagePosY+5),
new Point( thi s.imagePosX-5, t h i s .imagePosY+5),
new Point (t his .imagePosX-5, t h i s .imagePosY+10),
new Poi nt (t hi s.imagePosX-10, t h i s .imagePosY+10),
new Point (t hi s.imagePosX-10, t h i s .imagePosY+5),
new Po in t(this.imagePosX-5, t h i s .imagePosY+5),
new Point( thi s.imagePosX-5, t h i s .imagePosY-5),
new Po in t(t hi s.imagePosX-10, t h i s .imagePosY-5),
new Point( th is.imagePosX-10, t h i s .imagePosY-10)};

g .FillPolygon(bAlienColor, A l i e n ) ;
}

// complex shape - reusable as a single item


public void Tank(Graphics g, Brush bTankColor, Brush bC an nonColor) {
P o i n t [] tank = {
new Point( th is .imagePosX-10, t h i s .imagePosY-10),
new Po in t(this.imagePosX+10, t h i s .imagePosY-10),
new Point( th is .imagePosX+10, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY-5),
new Point( th is .imagePosX+5, t h i s .imagePosY+5),
new Point (t hi s.imagePosX+10, t h i s .imagePosY+5),
new Po in t(this.imagePosX+10, t h i s .imagePosY+10),
new Point (t his .imagePosX-10, t h i s .imagePosY+10),
new P oi nt(this.imagePosX-10, t h i s .imagePosY+5),
new Point( th is .imagePosX-5, t h i s .imagePosY+5),
new Point (t hi s.imagePosX-5, t h i s .imagePosY-5),
new P o i n t (t h i s .imagePosX-10, t h i s .imagePosY-5),
new Point( th is .imagePosX-10, t h i s .imagePosY-10)};

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).

// basic shape - reusable in many formats


public Point [] T r a p e z o i d O {
P o i n t [] Trapezoid = {
new Poin t( th is .imagePosX-5, t h i s .imagePosY-10),
new Poin t( th is .imagePosX+5, t h i s .imagePosY-10),
new Point (t hi s.imagePosX+10, t h i s .imagePosY),
new Point( th is .imagePosX-10, t h i s .i magePosY)};
return(Trapezoid);
}

T h e S h a rp T ria n g le is a lso u s e d to r e p re s e n t a n u m b e r of objects in c lu d in g C h a p te r 4’s


fa n (B a ttle T ennis).

// basic shape - reusable in many formats


public Point [] sharpTriangle () {
P o i n t [] sharpTriangle = {
new Poin t( th is .imagePosX, t h i s .imagePosY-5),
new Point (t hi s.imagePosX+3, t h i s .imagePosY+10),
new Point( th is .imagePosX-3, t h i s .imagePosY+10)};
return(sharpTriangle);
}

Inheriting from Shapes.cs—Patterns.cs

A n o th e r c la ss d ev elo p ed sp ecifically for th e g a m e s liste d in C h a p te r 4 is th e in h e ritin g


c la ss P a tte r n s . W e’re b u ild in g q u ite a la rg e c h a in , e.g., A n im a te d lm a g e .e s to P la y e r.c s to
P la y e rIm a g e A rra y .e s to S h a p e s .c s to P a tte r n s .c s . T h e g o al of th is c la ss is to c o n s tru c t a
s e t o f im a g e s t h a t m ove in u n is o n . T h e p a tte r n s a r e n u m b e re d , b u t th e r e co u ld a lso be a
n a m in g sc h e m e a s n ew p a t t e r n s a r e a d d e d to th e c lass. M e th o d s su c h a s F low er, TV, etc.

4 18
Chapter 5: Object-Oriented Design

a re re fe re n c e d fro m th e in h e rite d classes, a s th e o rig in a l fields a re u se d to c o o rd in ate th o se


p o in ts (see E x a m p le 5.72 a n d C R -R O M E x a m p le P a tte rn s .c s ).

E xam p le 5.72. P a tte r n s.c s

using System;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace GameClasses {
public class Patterns : Shapes {
public Patterns(int n) : base(O) {}

public Patterns(int posX, int posY) : base(O) {


imagePosX = posX;
imagePosY = posY;
isActive = false;
animationStep = DEFAULTSTEP;
}

public void ItemPattern28(Graphics g, Brush bltemColor,


Pen pltemColor, int current) {
if(current >= 0 && current <= 6) {
t h i s .Window(g, bltemColor);}
else if(current >= 7 && current <= 13) {
t h i s .Flower (g, bltemColor, pltemColor);}
else if(current >= 14 && current <= 20) {
this.TV(g, bltemColor, pltemColor);}
else if(current >= 21 && current <= 28) {
this.Lamp(g, bltemColor, bltemColor);
}
}

public void AlienPattern20(Graphics g, Brush bAlienColor,


int current) {
if(current >= 0 && current <= 4) {
t h i s .AlienO(g, bAlienColor);}
else if(current >= 5 && current <= 9) {
t h i s .Alienl (g, bAlienColor);}
else if(current >= 10 && current <= 14) {
t h i s .Alien2(g, bAlienColor);}
else if(current >= 15 && current <= 19) {
t h i s .Alien3 (g, bAlienColor);

419
C# and Game Programming

}
}

public void ItemPatternl(Graphics g, Brush bAlienColor,


int current) {
if(current >= 0 && current <= 4) {
t h i s .AlienO(g, bAlienColor);}
else if(current >= 5 && current <= 9) {
t h i s .Alienl(g, bAlienColor);}
else if(current >= 10 && current <= 14) {
t h i s .Alien2(g, bAlienColor);}
else if(current >= 15 && current <= 19) {
t h i s .Alien3(g, bAlienColor);
}

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 ).

E xam p le 5.73. G a m eS ta te.es

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

// Different "states" the game can be in.


public enum State : int {
Unknown = 0,
Started = 1,
Stopped = 2,
)

// Different "modes" the game can be run in.


[Flags]
public enum Mode : int {
Normal = 0,
SinglePlayer = 0,
TwoPlayer = 1,
Demo = 2,
}

// 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;
}

public G a m e S t a t e (int initialSpeed, State gameState) {


currentSpeed = initialSpeed;
currentState = gameState;
currentMode = Mode.Normal;
}

public GameState (int initialSpeed, State gameState,


Mode gameMode) {
currentSpeed = initialSpeed;
currentState = gameState;
currentMode = gameMode;
}
}
}

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 ).

E xam p le 5.74. G am eT im er.es


using System;
using System.Windows.Forms;
using Sy stem.Collections;

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;
}

// Simple start and stop functionality,


public void S t a r t () {g am e T i m e r .Start ();}
public void S t o p O {g a m e T im e r.Stop (); }

// Add an event to our game timer. Use stepFactor to control the


// frequency the given T i m ed Ev e nt fs Tick() will be called.
// Use the given "key" for future reference to this TimedEvent.
public void addEvent(TimedEvent timedEvent, int stepFactor,
string key) {
TimedEventNode node = new T i m e d Ev en tN od e();
node.data = timedEvent;
n o d e .timeStep = stepFactor;

422
Chapter 5: Object-Oriented Design

n o d e .stepCount = 0;
events.Add(key, node);
}

// Returns the event marked with the given key


public TimedEvent getEvent(string key) {
return ((TimedEventNode) e v e n t s [k e y ]).data;
}

// Removes an event from the list


public void r em o v e E v e n t (string key) {
e v e n t s .R e m o v e (key );
}

// Changes the step associated with the event indexed by key


public void C h a n g e S t e p (string key, int stepFactor) {
((TimedEventNode) e v e n t s [k e y]).timeStep = stepFactor;
}

// Tick() -- passes on tick event to proper TimedEvent objects


public void Tick(object sender, EventArgs e) {
IDictionaryEnumerator itemEnumerator = e v e n t s .GetEnumerator ();
TimedEventNode 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++;
}
}
}

// Helper class to hold a extra information relevant to


// timer event processing,
class TimedEventNode {
public int timeStep; // how many baselnterval ticks to wait
public int stepCount; // counter to compare with timeStep
public TimedEvent data; // the TimedEvent object
}
}
}

423
C# and Game Programming

TimedEvent.es

T im e d E v e n t.e s is a c la ss r e p r e s e n tin g a tim e r; it is u s e d to m o n ito r e v e n ts b a s e d on a s e t


n u m b e r of p ro c e ssin g cycles. I t c a n m o n ito r t h a t a n e v e n t h a p p e n s a s e t n u m b e r of tim e s,
etc. D e riv in g fro m th is c la ss a n d o v e rrid in g th e Tick () m e th o d c a n allo w fo r c u sto m
b e h a v io r (see E x a m p le 5.75).

E xam p le 5.75. T im ed E v en t.es

using System;

namespace GameClasses {
public delegate void TickHandler(TimedEvent e, Object payload);

public class TimedEvent {


// Member fields
public int ticks;
public int tickCounter;
public bool isCountdown;
public bool isActive;
public TickHandler remoteHandler;
public 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));
}

public TimedEvent(TickHandler handler) {


SetTickHandler(handler);
}

public TimedEvent(int numTicks, TickHandler handler) {


SetCountdown(numTicks);
SetTickHandler(handler);
}

public void SetTickHandler(TickHandler handler) {


remoteHandler = handler;
}

424
Chapter 5: Object-Oriented Design

public void S e t C o un td ow n(int numTicks) {


isCountdown = numTicks > 0;
ticks = numTicks;
tickCounter = ticks;
}

public void Tick() {


if (!isActive)
return;

// Call any custom function


remoteHandler(this, payload);

// decrement the counter


if (isCountdown)
if (tickCounter > 0)
tickCounter--;
else
isActive = false;
}

public void R e s e t () {
tickCounter = ticks;
isActive = true;
}

// Dummy for default tick-handier


public void DoNothing(TimedEvent e, Object o)

Utils.cs

T h e file U tils c la s s is a c o m b in a tio n o f b a sic u tilitie s w ith a focus on s o u n d p ro d u c tio n


u s in g W in d o w ’s M u ltim e d ia . I t is in te n d e d to sim p lify s o u n d re fe re n c e s th r o u g h o u t o u r
W in d o w s F o rm s a n d G D I+ g a m e s a n d a c t a s a b a c k u p /a lte r n a tiv e fo r D ire c tS o u n d (see
E x a m p le 5.76).

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) ;

// Static Variable .config file's contents


public static System.Collections.Spec ia li ze d.NameValueCollection
Config =
System.Configuration.ConfigurationSettings.AppSettings;

// Error-handling Loadlmage function


public static Image Loadlmage(String strFileName) {
Image imgLoad = null;
try {
imgLoad = I m a g e .F r o m F i l e (strFileName);
} catch (FileNotFoundException ex) {
M e s s a g e B o x .S h o w ("Please check that the following file " +
"exi st s:\n\n" + ex.Message + "\n\nCorrect the file " +
"referenced in the config file.", "File Not Found!");
A pp l i c a t i o n .E x i t ();
}

return imgLoad;
}

// PlaySound simple pass-through function. Removes dependency for


// other classes to reference winmm.DLL.
public static void PlaySound(String strFileName) {
ThreadedSound snd = new T h r e a d ed So un d(strFileName);
Thread worker = new Thread(new T h r e a d S t a r t (s n d .P l ay ));
w o r k e r .Start ();
}

426
Chapter 5: Object-Oriented Design

class ThreadedSound {
public string strFileName;

public T h r ea de dS ou nd (string file) {


strFileName = file;
}

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

W all is a b a sic c o n c e p t u s e d to lim it th e p a th s of o u r c h a ra c te rs , b o th frie n d a n d foe. T h e


c o n s tru c tio n of a w a ll is b a s e d on its w id th , le n g th , a n d th ic k n e s s . T h e w a ll is p o sitio n e d
u s in g s ta n d a r d C a r te s ia n c o o rd in a te s. T h e b ru s h e s a r e u se d to d ra w G D I+ m odels, w h ile
D ire c tX m e re ly r e tr ie v e s th e c o o rd in a te s a n d h a n d le s th e d ra w in g fro m in s id e th e g a m e
(see E x a m p le s 5 .7 7 -5 .7 9 ).

E xam p le 5.77. W all.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;

public int orientation;


public Point start;
public int length;
public int thickness;

427
C# and Game Programming

private Brush brush;


private Color color;
private Rectangle rect;

public Wall(int orientation, Point start, int length,


Color color) :
this(orientation, start, length, DEF_THICKNESS, color) {}

public Wall(int orientation, Point start, int length,


int thickness, Color color) {
t h i s .orientation = orientation;
this.start = start;
this.length = length;
t h i s .thickness = thickness;
this.color = color;

rect = new R e c t a n g l e (start, (orientation == HORIZONTAL) ?


new Size(length, thickness) : new Size(thickness,
length));
this.brush = new So lidBrush(this.c olor);
}

E x a m p l e 5 .7 8 . I n t e r s e c t s .

public bool Intersects(Animatedlmage o b j ) {


int x = o b j .imagePosX, y = o b j .imagePosY;
int x2 = o b j .imagePosX + o b j .imageWidth;
int y2 = o b j .imagePosY + o b j .imageHeight;
int _x = rect.X, _y = rect.Y;
int _x2 = rect.X + rect.Width, _y2 = rect.Y + rect.Height;

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

public void Display(Graphics g) {


g .FillRectangle(brush, r e ct);
}

428
Chapter 5: Object-Oriented Design

public Rectangle g et R e c t a n g l e () {
return(rect);
}
}
}

Introducing D irect3D

M a n a g e d D irect3 D is a low -level g ra p h ic s a p p lic a tio n /p ro g ra m m in g in te rfa c e u se d to r e n ­


d e r tw o- a n d th re e - d im e n s io n a l im a g e s fo r s ta tic a n d a n im a te d p ro je c ts r e la tin g to b o th
b a sic a n d g ra p h ic a lly in te n s e p ro g ra m s. M a n a g e d D irect3 D ta k e s a d v a n ta g e of h a rd w a re
a c c e le ra tio n to p ro d u c e h ig h - q u a lity r e a l tim e g ra p h ic s, w h ile r e q u irin g o n ly a m in im a l
a m o u n t o f d o w n tim e r e la tin g to th e le a rn in g c u rv e a s c o m p a re d to th e p e rv io u s v e rsio n s
o f D irectX . T h e M a n a g e d D ire c t3 D ’s n a m e s p a c e in c lu d e s n e a rly 300 c la sse s, s tr u c tu r e s ,
e n u m e r a tio n s , a n d d e le g a te s , e a c h of w h ic h in c lu d e s a la rg e s e t of m e m b e rs, p ro p e rtie s ,
a n d field s. F o rtu n a te ly , m o st a p p lic a tio n s re q u ire o n ly a few com m on re fe re n ce s, u s u a lly
b e g in n in g w ith th e device c la ss (see D ire c t 3D ’s D evice C la ss for d e ta ils).

D irect3D ’s Device Class

T h e device class in c lu d e s th r e e co n stru c to rs, of w h ich only one is u se d in M a n a g e d D irectX :


p u b lic D e v ic e (in t adapter, D e v i c e T y p e deviceType, Control renderWindow,
CreateFlags behaviorFlags, PresentParameters [ ] presen ta tionParameters);. T h e
f ir s t p a r a m e te r, a d a p ter , re fe rs to th e p h y sic a l d evice re fe re n c e d b y th e c o m p u te r w ith a
unique a d a p ter identifier (n o te t h a t zero in d ic a te s th e d e fa u lt). T h e deviceTypes in c lu d e
H a rd w a re , Reference , a n d Software. H ardw are r e f e r s to d ire c t access, w h ile Reference
r e f e r s to e m u la tio n . (E m u la tio n is r e q u ir e d w h e n th e h a r d w a r e does n o t s u p p o rt th e r e ­
q u e s te d fe a tu re .) T h e Reference r a s te r iz e r is m u ch slo w er a n d re q u ire s t h a t a ll u s e rs h a v e
th e S D K in s ta lle d ; h e n c e , i t s h o u ld o n ly b e u s e d fo r d e b u g g in g . T h e re is a lso a c u sto m
S o f tw a r e r a s t e r i z e r , w h ic h has lim ite d a v a ila b ility . The b e h a v io r F la g s
(b e h a v io r F la g s . S o f t w a r e V e r t e x P r o c e s s in g ) c o n tro l th e d ev ic e’s b e h a v io r, sp e c i­
fy in g o u r p ro c e ssin g u n it, e.g., th e C P U a n d G P U . (T he G P U offers th e b e s t p e rfo rm a n c e ;
a g a in , th is d e p e n d s o n h a r d w a r e a v a ila b ility ). T h e c o n s tru c to r presentationParam eters is
u s e d to co ntro l p re s e n ta tio n , w h ich in c lu d e s tw o ke y m em b ers: Windowed a n d SwapEffect.
T h e W indow ed m e m b e r (a B oolean ty p e) is u se d to d e te rm in e th e w indow ’s s ta tu s (tru e for

429
C# and Game Programming

W in d o w e d m ode, fa ls e fo r fu ll sc re e n m ode), w h ile S w a p E ffe c t is u s e d to c o n tro l b u ffe r


b e h a v io r. SwapEffect.Copy, SwapEffect.Discard, and SwapEffect.F l i p a r e u s e d to
copy, d isc a rd , a n d flip, re sp e c tiv e ly . F l i p c r e a te s a n e x tr a b ac k b u ffer, w h ile C o p y r e ­
q u ire s t h a t w e s e t o u r b a c k b u ffe rs to one; D i s c a r d sim p ly d is c a rd s th e b u ffe r’s c o n te n t.
D evice a lso in c lu d e s th e m e th o d s C l e a r a n d P r e s e n t . P r e s e n t is th e s im p le r of
th e tw o, w ith no a r g u m e n ts , a n d is u s e d to p r e s e n t o u r g ra p h ic s to th e sc re e n . C l e a r
in c lu d e s a m in im u m of fo u r p a r a m e te rs : ClearFlags, Color, float zdepth, a n d int
stencil. F o r t h e tim e b e in g w e ’ll lim it th e s e s e ttin g to t h e i r m o s t b a s ic le v e ls:
(ClearFlags. Target, Color. Empty, O.Of, o). W e’ll also n e e d to b u ild a W indow s a p p li­
catio n , a d d in g th e re fe re n c e s D irectX , D irectX .D irect3D , a n d D irect3D X . (N ote t h a t w e do
n o t in c lu d e th e p h r a s e using Mi cr os of t.D ir ectX.Direct3DX; see E x a m p le 5.80 on th e
CD-ROM.)

Displaying 2D Images using Direct3D

A s w ith D ire c tD ra w , D ire c t3 D u s e s a s im p le D ra w c o m m a n d to d is p la y its im a g e s, h o w ­


ever, th e D ire c t3 D ’s v e rs io n of th e D ra w co m m a n d r e q u ire s se v e n a r g u m e n ts n a m e ly th e
s p rite T e x tu re , s p rite , te x tu re S iz e , sc a lin g , ro ta tio n , tr a n s itio n , a n d color. T h e f ir s t th r e e
a r g u m e n ts p e r ta in to th e b o d y of th e b itm a p , w ith s p rite T e x tu re re fe re n c in g th e a c tu a l
lo a d e d im a g e o r b itm a p file (*.bm p), s p rite is u s e d to lin k o u r b itm a p to th e D evice class,
a n d te x tu re S iz e is u s e d to s e t th e size of t h a t te x tu r e . S c a lin g th e n d ic ta te s th e size of th e
re n d e re d im a g e , w ith ro ta tio n C e n te r, ro ta tio n , a n d tr a n s la tio n r e la tin g to th e c h a ra c te r s
p o sitio n (tr a n s la tio n p la c e s th e im a g e u s in g C a rte s ia n coo rd in ates), color, q u ite obviously,
d ic ta te s th e im a g e s color.
H e re w e ’ll also w a n t to in tro d u c e th e m e th o d s u s e d to c o n ta in o u r d ra w in g fu n c tio n ,
a p p r o p r ia te ly te r m e d B e g i n S c e n e ( ) ; EndScene ( ) ; . T h e se c a n be b u ilt in to a
u se r-d e fin e d g ra p h ic s call or a s p a r t of th e O n P a in t re fe re n ce (see E x a m p le 5.81 on th e CD-
ROM).

D irect3D ’s 2D Animation—Basics

Im a g e p o sitio n is co n tro lled b y th e tr a n s la tio n co o rd in a te s x, y, a n d p o te n tia lly 2. A d d in g or


s u b tr a c tin g fro m th e s e v a lu e s , in e sse n c e , c re a te s m o v e m e n t. T h is m o v e m e n t, h o w ev er,
sh o u ld n o t b e co n sid e re d tr u e a n im a tio n , b u t r a th e r only a sim p le form of d isp la c e m e n t. To

430
Chapter 5: Object-Oriented Design

c re a te th e effect of tr u e a n im a tio n , th e p ro g ra m m e r w o u ld h a v e to in c lu d e som e v is u a l


c h a n g e s, a t u r n to th e left, a s te p to th e rig h t, etc. To do th is , w e ’ll n e e d to in c lu d e s e v e ra l
a lte r n a tiv e im a g e s; th e s e w ill be s to re d to th e spr i teTexture, w h ic h w ill now be r e f e r ­
e n c e d a s a n a rra y . H e re , I ’ve also in c lu d e a sim p le try -c a tc h block to m o n ito r th e n ew
im a g e s. N o te t h a t , w ith D ire c t3 D , a m is s in g file does n o t h a l t c o m p ila tio n (see E x a m p le
5.82 on th e CD -RO M ).

Game 6 —Ground Assault


Ground A ssa u lt is a com bination of all th e previous gam es, as w ell as several of th e cla sses
w e ju st discussed. Once again, w e n eed to lay out a sim ple plan, develop som e characters,
w eapons, and include a lin e of m ovem ent— th is tim e, I think w e’ll even develop a few w alls.

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

1. R e d e sig n c h a r a c te r s to in c lu d e bodies, also, u se on ly one


c h a r a c te r fro m e a c h color g ro u p .
2. R e d e s ig n th e h e ro so t h a t h e ’s n o t lo o k in g u p , a n d give h im th e
a b ility to t u r n in a ll fo u r d ire c tio n s .
3. R e d e s ig n th e m is s ile s to in c lu d e a ll e ig h t d ire c tio n s .
4. A d d fo u r w a lls t h a t a r e re p o sitio n e d a f te r e a c h n ew lev el (se t u p
th e f ir s t p a t t e r n to r e p e a t a f te r you co m p le te th e fo u rth ).
5. G ive th e w a lls a d is tin c t color.
6. G ive th e h e ro th r e e liv es.
7. H a v e h im sco re a s e t n u m b e r of p o in ts fo r k illin g e a c h a lie n .

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 ).

Game 7 —Rat Racer


F o r o u r se v e n th gam e, w e’ll b u ild a sim p le m aze w ith som e o b stac les a n d a goal. T h e ste p s
a r e fa irly ro u tin e : b ra in s to rm in g , d ra w in g o u t th e c h a ra c te rs , a n d a p p ly in g th e k e y fu n c ­
tio n s. H e re ’s a m in i-v e rsio n o f th o s e ste p s.

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 .

1. Two m ice a r e r a c in g to se e w ho c a n e a t th e m o st c h ee se.


2. T h e r e ’s a m a z e t h a t th e y m u s t tr a v e r s e .
3. T h e re w ill b e fo u r c a ts s ittin g a t e a c h c o rn e r of th e m a ze.
4. I f you m ove too close to a n y of th o s e c a ts , y o u ’ll g e t e a te n .
5. I f o n e p la y e r d ies, th e o th e r s till m u s t e a t a ll th e ch e ese.
6. W a lk in g in to th e w a lls w ill k ill th e m ice.
7. T h e c h e e se w ill b e p la c e d ra n d o m ly a c ro ss th e b o a rd .
8. I f a ll th e c h e e se is e a te n th e c h e e se w ill re s e t.

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.

1. B u ild a sim p le s tr u c tu r e a n d re fe re n c e it fro m th e m a in m e th o d .


Questions
T h e n , u s in g p u b lic fie ld s, re b u ild t h a t s tr u c tu r e a s a c lass.
2. F ro m Q u e s tio n 2, c o n v e rt t h a t c la s s ’ p u b lic fie ld s in to p ro te c te d
fie ld s (b u ild a s m a n y s e c o n d a ry m e th o d s a s y o u n e e d to g e t th e
job done).
3. F ro m Q u e s tio n 3, c o n v e rt th o s e fie ld s in to p r iv a te m e m b e rs.
(H in t: You m a y n e e d to a d d a d d itio n a l m e th o d s.)
4. W rite a c la ss t h a t allo w s fo r b o th o v e rlo a d e d a r ith m e tic a n d
c o m p a ris o n o p e ra to rs .
5. W rite a s im p le p u b lic, n e s te d class, a n d th e n re p la c e t h a t n e s te d
c la s s w ith a n in h e r ite d c la ss.

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

p ro fe ssio n ? ” T h e a n s w e r to th e s e q u e s tio n s is, “T h ro u g h c o n tin u e d stu d y .” You’ll w a n t to


t a k e a good, h a r d look a t th e s p e c ia ltie s in v o lv ed w ith b u s in e s s a n d g a m e p ro g ra m m in g ,
a s w e ll a s m a th e m a tic s , e le c tro n ic s, a n d e n g in e e rin g . F o r som e, a college d e g re e w ill be
th e n e x t ste p ; fo r o th e rs , th e M C A D /M C SD w ill se e m lik e th e b e s t ro ad . U ltim a te ly , th e s e
choices a r e le ft to you.
T h e b o o k ’s C D R O M in c lu d e s a sp e c ia l se le c tio n of te x t re fe re n c e s t h a t m y a id you in
th is journey. I’ve also in c lu d e d p la y a b le a n d p ro ject v e rsio n s of a ll th e g am es, a s w ell a s th e
o rig in a l a r t, so u n d clips, a n d so u rce code to m a k e it p o ssib le fo r you to develop new a n d /o r
e x te n d e d v ersio n s. To access th e ca ta lo g an d /o r th e a lte r n a tiv e files, sim p ly se a rc h th ro u g h
th e C D R om u s in g y o u r W in d o w s’ e x p lo re r a n d access th e a p p ro p ria te files.
T h e r e le a s e v e rs io n s of th e g a m e s a r e a lso lis te d in a c c o rd a n ce w ith th e ir c h a p te r s
(C h a p te rX G a m e T itleX B in X R eleaseX G am e T itle .e x e ), a n d c a n also b e a c c e sse d th ro u g h
W in d o w s’ e x p lo re r; h o w ev er, fo r b e s t g a m e play, it is re c o m m e n d e d t h a t th e s e g a m e s be
s to re d on th e h a r d d riv e.

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

as default for new sbyte typeof

base delegate foreach null sealed uint

bool do goto object short ulong

break double if operator sizeof unchecked

byte else implicit out stackalloc unsafe

case enum in override static ushort

catch event int params string using

char explicit interface private struct virtual

checked extern internal protected switch void

class false is public this volatile

const finally lock readonly throw while

continue fixed long ref true

It is important not to intermix reserved identifiers with programmer-generated


references. However, if a situation arises where such a naming conflict cannot
be avoided, it is possible to disassociate that identifier from the compiler
using the @ symbol (see Example A .l).

E xam ple A .l.


using System;
namespace Appendix_A {
class Classl {
[STAThread]
static void M a i n (s t r i n g [] args) {
int @true = 32 5;
string @while = "Salvatore A. Buono";
Co n s o l e .WriteLine(@true);
C o n s o l e .WriteLine(@while);
}
}
}

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).

E xam ple B .l.


public abstract class Area {}
class Appendix_B {
static void M a i n O {}
}

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).

E xam ple B.2.


public class Appendix_B {
public static void M a i n O {
object MyString = new object 0 ;
string s = MyString as string;
}
}

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

E xam ple B.3.


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 B a s e C l a s s O {}
p u b l i c vi r t u a l v o i d D i s p l a y A r e a () {}
}
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 () {}
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 () {
b a s e .D i s p l a y A r e a ();
}
static void Main 0 {}

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).

E xam ple B.9.


class Appendix_B {
static void M a i n O {
char Symbol = 'A';
}
}

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).

E xam ple B.10.


class Appendix_B {
static void M a i n O {
byte Max255 = 254;
checked{Max255++;}
}
}

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).

E xam ple B.14.


class Appendix_B {
static void M a i n O {
decimal Numberl, Number2;
Numberl = 1.0M;
Number2 = 1.1m;

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).

E xam ple B.15.


using System;
class Appendix_B {
static void M a i n O {
int byNumber = C o n s o l e .R e a d ();
switch (byNumber) {
default:
break;
}
}
}

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

Exam ple B.16.


p u b l ic d e le g a t e v o id T r y D e le g a t e ( ) ;
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 ( ) {
T r y D e le g a t e ( ) ;
}
p u b lic s t a t ic v o id T r y D e l e g a t e () {}
}

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).

E xam ple B.20.


class Appendix_B {
public enum Months {Jan = 1, Feb, Mar, Apr,
May, Jun, J u l , Aug, Sep, Oct, Nov, Dec}
public enum Day {AprilFools = 1, Birthday = 16,
XMas = 25, Feb29 = 29, NYeve = 31}
public enum Year {Year2 = 2002, Y e a r 3 , LeapYear}
static void Main() {}
}

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).

E xam ple B.28.


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 {
fo r (in t i = 0; i < 5; i+ + ) {/ * */}
}
}

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).

E xam ple B.29.


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 {

450
Appendix B: Reserved Identifiers Defined

c h a r [] in t e g e r = { ' a ' , 1g 1 , 1n ' # ' u ' } ;


fo re a c h (c h a r f in d in in t e g e r ) { / * * / }
}
}

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).

E xam ple B.35


u s i n g System;
namespace Appendix_B {
i nter f a c e B a s e l n t e r f a c e {
short W i d t h {get; set;}
short L e n g t h {get; set;}
}
p u b l i c class Ba s e C l a s s : B a s e l n t e r f a c e {
p r i v a t e short BIWidth;
p r i v a t e short BILength;
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 Width, short y) {
B I W i d t h = Width;
B I L e n g t h = y;
}
p u b l i c short W i d t h {
g e t { r e t u r n ( B I W i d t h ) ;}
s e t { B I W i d t h = value;}
}

453
C# and Game Programming

public short Length {


g e t {return(BILength);}
set{BILength = value;}
}
public static void M a i n () {}
}
}

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

public static void Test(object ob) {


TestClass test;
- if (ob is TestClass) {
test = (TestClass)ob;
}
}
public static void M a i n () {}
}
}

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

public new short X {get{return(x);}}


static void Main(){}
}
}

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);
}

static void TheRace(out int Num) {


Num = 1;

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() {
}
}

private, protected, and public


P riv a te , p r o t e c t e d , a n d p u b l i c a re c la ss o r s tr u c tu r e m e m b e rs t h a t allow for r e ­
s tric te d or lim ite d access b a s e d on u se r-d e fin e d m e th o d s w ritte n specifically for th o se v a l­
u es. T h e se u s e r-d e fin e d m e th o d s a re d e c la re d a s p a r t of t h a t c la ss’ in te r n a l s tr u c tu r e (see
E x a m p le s B .48-B .50).

E xam ple B.48.


namespace Appendix_B {
class BankAccount {
private string first_name;
private void ReadFiles(ref BankAccount acc) {}
static void M a i n () {}
}

Note: While p r i v a t e is the default setting, many programmers choose to


explicitly restate that command to remove any ambiguity.

E xam ple B.49.


namespace Appendix_B {
class BankAccount {
protected string first_name;
protected void ReadFiles(ref BankAccount acc) {'
static void Main() {}
}
}

460
Appendix B: Reserved Identifiers Defined

Exam ple B.50.


namespace Appendix_B {
class BankAccount {
public string first_name;
public void ReadFiles(ref BankAccount acc) {}
static void Main() {}
}
}

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).

E xam ple B.51.


class Appendix_B {
public readonly double variable2 = 3.14159;
static void M a i n () {}
}

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);
}

static void TheRace(ref int Num) {}


}

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 ();
}

static int Ran d o m N u m b e r () {


r e t u r n (0) ;
}
}

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).

E xam ple B.57.


using System;
class Appendix_B {
static unsafe void M a i n O {
Console.WriteLine ("Byte = " + sizeof(byte));

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).

E xam ple B.60.


class Appendix_B {
static void Main() {
string MyDog = "Brownie";
}
}

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

N o te t h a t w h ile th e u se of a C++ sty le te rm in a tin g sem icolon is allow ed, it is n o t re q u ire d


w h e n w o rk in g w ith C#.

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.

E xam ple B.62.


class Appendix_B {
static void M a i n O {
int Grades = 1;
switch (Grades) {
case 1:
break;
default:
break;
}
}
}

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).

E xam ple B.69.


class Appendix_B {
static void M a i n O {
ulong Numberl = 1;
}
}

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).

E xam ple B.70.


class Appendix_B {
static void Main () {
byte Max255 = 255;
unchecked {Max255 += 1 ;}
}
}

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

Exam ple B.71.


class Classl {
static unsafe void M a i n O {}
}

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).

E xam ple B.72


class Appendix_B {
static void M a i n O {
ushort Numberl = 1;
}
}

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).

E xam ple B.73.


using System;
class Appendix_B {
static void M a i n O {}
}

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.

E xam ple B.75.


class Appendix_B {
static void M a i n (){}
}

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).

E xam ple B.76.


class Appendix_B {
public volatile char variable3 = 'A';
static void Main(){}
}

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).

E xam ple B.77.


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 {
w h ile ( t r u e ){}
}
}

471
Appendix C
Appendix C: Accessors

get & set


T he g e t a n d s e t accessors a r e n ’t officially keyw ords, ra th e r, th e y a re p a ra m e te rle s s m e th ­
ods n a m e d to m a tc h c e rta in fields a n d u se d in c lasses a n d in te rfa c e s t h a t hold a body of
ex e c u ta b le d a ta p e rta in in g to th e sto ra g e a n d re trie v a l of th o se fields. T h e ir ex ecu tab le
s ta te m e n ts m a y in clu d e calcu latio n s, conversions, a n d a la rg e h o st of o th e r ta s k s , b u t th e ir
u n d e rly in g p u rp o se m u s t in c lu d e re a d in g or re co rd in g to th o se p ro p e rtie s. T h e body of a n
accesso r is c o n sid e re d e q u iv a le n t to a m e th o d a lth o u g h th e y do n o t in clu d e id e n tity sig n a ­
tu re s . T h e g e t accesso r r e tu r n s a v a lu e a n d m a y be se t to th ro w a v a lu e w h e n needed; in
c o n tra s t, th e s e t accesso r is a lw a y s se t to void. T h e k eyw ord v a l u e is also u se d a s a n
im p lic it p a r a m e te r w ith s e ttin g fields, th u s it ta k e s on th e v a lu e of a n y p a s s e d v a ria b le s.
T h e g e t a n d th e s e t accessors alw ay s s h a re th e sa m e u ser-d efin ed nam e , th u s th e y c a n n o t
e x ist in th e sa m e b a se class. I t is th e n co n sid ered n a tu r a l to place th e s e t accessor in th e
b a se class w ith th e g e t accesso r lis te d in th e n e s t d e riv e d class. I t is also im p o rta n t to
re m e m b e r t h a t th e v alu e re trie v e d by th e g e t p ro p e rty is for referen ce only, w hile th e v alu e
re c o rd e d in th e s e t p ro p e rty is w rite only (see E x a m p le C. 1).

E xam ple C .l.


namespace Appendix_C {
public class BaseClass {
public short width;
protected B a s e C l a s s () {}
public short Width {set{width = value;}}
}
public class DerivedClass : BaseClass {
protected D e r i v e d C l a s s () {}
public new short Width {get{return(width);}}
static void M a i n O {}
}
}

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

A ssig n m en t, add, subtract, m ultiply, divide, r em a in d er...


/- %= « = » =
| = &= A =

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 ).

E xam ple E .l. The m essa g e box.


using System;
using System.Drawing;
using Syst e m .Collections;
using System.ComponentModel;
using System.Windows.F o r m s ;
using System.Data;
using System.10;
using System.Runtime.InteropServices;

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 ());
}

private void Forml_Load(object sender, S y s t e m .EventArgs e){}

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

Exam ple E.2.


M essageBo x .S h o w ("Place message Here", "Place caption h e r e " ) ;

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);

W e c a n also t e s t a n d b u ild n ew a c tio n s b a s e d on th e re s p o n s e s rec e iv e d by m e ssa g e


boxes (see E x a m p le s E .1 8 -E .2 6 ).

479
C# and Game Programming

Exam ple E.18.


DialogResult result = M e s s a g e B o x .S h o w ("Place message here",
"Place caption here", MessageBoxButtons.O K ) ;

if (result == Dialog R e s u l t .OK) {


PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0) ;
}

E xam ple E.19.


DialogResult result = M e s s a g e B o x .S h o w ("Place message here",
"Place caption here", MessageBoxButtons.OKCancel);

if (result == Dialog R e s u l t .Can c e l ) {


PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0) ;
}

Exam ple E.20.


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 == 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) ;
}

E xam ple E.22.


DialogResult result = M e s s a g e B o x .S h o w ("Place message here",
"Place caption here", MessageBoxButtons.YesNoCancel);

if (result == Dialog R e s u l t .C ancel) {


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) ;
}

E xam ple E.25.


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 == Dialog R e s u l t .Ignore) {


PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0) ;
}

E xam ple E.26.


DialogResult result = M e s s a g e B o x .Show(this, "Place message here",
"Place title here", MessageBoxButtons.YesNoCancel);

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.

W e’ll also w a n t to ta k e a d v a n ta g e of tw o of th e u se fu l M essageB oxO ptions, R ig h tA lig n a n d


R tlR e a d in g . T h e se a r e e s s e n tia lly m e s sa g e a lig n m e n t tools w ith R ig h tA lig n m o ving th e

481
C# and Game Programming

m e ssa g e te x t to th e fa r r ig h t ( u s e r ’s p e rsp e c tiv e ), a n d R tlR e a d in g m oving th e m e ssa g e to


th e le ft (p lacin g th e icon on th e rig h t). W e’ll c a n also se t a d e fa u lt, or p re s e le c te d b u tto n ;
th is w ill n o t affect th e u s e r ’s a b ility to choose, b u t it g e n e ra lly serv es a s th e re c o m m e n d e d
o p tio n (see E x a m p le s E .2 7 -E .2 9 ).

E xam ple E.27.


DialogResult result = M e s s a g e B o x .S h o w (this , "Place message here"
"Place caption here", MessageBoxButtons.Y esNoCancel,
Messag eBoxIcon.Question, MessageBoxDefaultButton.B u t t o n l ,
MessageBoxOptions.R ightAlign);

if (result == Dialog R e s u l t .Y e s ) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0 , 0 ) ;

Exam ple E.28.


DialogResult result = M e s s a g e B o x .Show(this, "Place message here",
"Place caption here", MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question, MessageBoxDefaultButton.But t o n 2 ,
MessageBoxOptions.R tlReading);

if (result == DialogResult.No) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0, 0);
}

Exam ple E.29.


DialogResult result = M e s s a g e B o x .S h o w (t h i s , "Place message here",
"Place caption here", MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question, MessageBoxDefaultButton.B u t t o n 3 ,
MessageBoxOptions.R t l Reading);

if (result == DialogResultCancel) {
PlaySound(@"C:\SourceCode\Fire.w a v " , 0 , 0)

It is also important to remember not to place message boxes such as these


inside of OnPaint or other graphics handling methods, the result is a potential
invalidating loop.

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.

Points & Size


T h e f ir s t a sp e c t to d ra w in g is th e p o i n t re fe re n ce , w h ic h d e sc rib e s th e lo c a tio n s t h a t
d e lin e a te s h a p e s. A p o in t is d e c la re d u s in g th e C a rte s ia n c o o rd in a te sy ste m (th e x, y coor­
d in a te sy ste m ), w h e re x is th e h o riz o n ta l p o sitio n a n d y is th e v e rtic a l p o sitio n a s in
P o i n t ( i n t x, i n t y). O nce o u r p o in ts a re d e fin e d , w e’ll th e n n e e d to in c lu d e a s i z e r e f e r ­
ence, w h ic h also re lie s on a n x ,y sch em e— S i z e ( i n t x , i n t y ) . B o th p o i n t a n d S i z e
c a n be re fe re n c e d a s in d iv id u a l o b jects o r a s p a r t of a specific s h a p e (see E x a m p le F .l).

E xam ple F .l.


using System;
using Sy s t e m .Dra w i n g ;
using System.Windows.F o r m s ;
namespace Appendix_F {
public class Forml : System.Windows.F o r m s .Form {
public F o r m l () {}
protected override void OnPaint(PaintEventArgs e) {
Point point = new P o i n t (10, 15);
Size size = new Size(15, 200);
Brush GreenBrush = new SolidBrush (Color.G r e e n ) ;
Graphics MyText = e.Graphics;
Font Normal = new Font("Times New Roman", 14, Fon t S t y l e .B o l d ) ;
M y T e x t . Drawstring("TEST", Normal, GreenBrush,
new Rectangle(point, size));
M y T e x t .D r a w s t r i n g ("TEST", Normal, GreenBrush,
new Rectangle(new P o i n t (50, 15), new S i z e (15, 200)));
}
static void Main() {
A p p l i c a t i o n .Run(new F o r m l ());
}
}
}

483
C# and Game Programming

PointF and SizeF are used to indicate floating point values, which are necessary
when drawing with pixels.

Brushes & Pens


We c a n also u s e w h a t a re k n o w n a s brushes a n d pens to e n h a n c e g ra p h ic s a n d te x t-
s u p p o rte d d isp la y s. B ru s h e s a n d p e n s a re d e c la re d a n d acc essed in b a sic a lly th e sa m e
m a n n e r, w ith b ru s h e s b e in g u s e d for te x t a n d to fill, r a th e r t h a n to d ra w sh a p e s. B ru s h e s
a re also a b s tr a c t by d e fin itio n a n d h e n c e c a n n o t be in s ta n tia te d . T h e re a re , how ever,
fiv e d e r i v e d c l a s s e s u s e d to c r e a t e d i f f e r e n t t y p e s o f b r u s h e s : H a t c h B r u s h ,
L in e a r G r a d ie n tB r u s h , P a th G r a d ie n tB r u s h , S o lid B ru sh , a n d T e x tu re B ru s h . P e n is also
d e riv e d fro m th e a b s tr a c t b r u s h class; it c a n be w ritte n to ta k e a d v a n ta g e of a ll five of
th e d e riv e d c la sse s, b u t it h a s a c o n s ta n t color r a t h e r th a n a g ra d ie n t. F o r o u r p u rp o se s,
w e’ll w a n t to look a t how to d e c la re a n d re fe re n c e b o th th e b a sic S o lid B ru sh a n d th e p e n
(see E x a m p le F.2).

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 ) ;

Graphics Figures = t h i s .C r e a t e Graphics();


Pen RedPen = new P e n ( Color.R e d ) ;
Pen GreenPen = new P e n(Color.G r e e n ) ;
Pen BluePen = new P e n ( Color.B l u e ) ;
Pen YellowPen = new Pen(C o l o r .Y e l l o w ) ;

F i g u r e s .DrawLine(RedPen, pointl, point2);


F i g u r e s .DrawLine(GreenPen, 250, 10, 10, 250);
F i g u r e s .DrawLine(BluePen, pointfl, pointf2);
F i g u r e s .DrawLine(YellowPen, 10F, 125F, 250F, 1 2 5F);}
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 ());
}
}
}

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

D raw C u rv e(C o lo r, A rra y O fP o in ts); D raw 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 e n sio n ); D ra w C u rv e (C o lo r, A r r a y O f P o in ts , O ffse t, S e g m e n t); D ra w C u rv e (C o lo r,
A rra y O fP o in ts, T ension); a n d D raw C u rve(C olor, A rra y O fP o in ts)— see E x a m p le F.4.

E xam ple F.4.


using System;
using System.Drawing;
using System.Windows.Fo 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) {
PointF pointfl =new PointF(125F, 10F) ;
PointF pointf2 =new PointF(125F, 12 5 F ) ;
PointF pointf3 =new PointF(250F, 2 5 0 F ) ;
PointF pointf4 = new P o i n t F (250.OF, 150.OF);
PointF pointf5 =new PointF(150F, 10 0 F ) ;
PointF pointf6 =new PointF(250F, 2 0 0 F ) ;
PointF pointf7 =new PointF(125F, 12 5 F ) ;

PointF [] ArrayOfPoints = {pointfl, pointf2, pointf3, pointf4,


pointf5, pointf6, pointf7};

Graphics Figures = t h i s .C reateGraphics();


Pen RedPen = new Pen( C o l o r .R e d ) ;

F i g u r e s .DrawCurve(RedPen, ArrayOfPoints, 2, 4, 1.0F);


F i g u r e s .DrawCurve(RedPen, ArrayOfPoints, 0);
F i g u r e s .DrawCurve(RedPen, A rrayOfPoints);
}
static void Main() {
A p p l i c a t i o n .Run(new F o r m l ());
}
}
}

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

Exam ple F.5.


using System;
using System.Drawing;
using System.Windows.F o rms;
namespace Appendix_F {
public class Forml : System.Windows.F o r m s .Form {
public F o r m l () {}
protected override void OnPaint(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, 10F) ;
PointF pointf2 =new PointF(125F, 125F);
PointF pointf3 =new PointF(250F, 2 5 0 F ) ;
PointF pointf4 =new P o i n t F (250.OF, 150.OF);
PointF pointf5 =new PointF(150F, 1 0 0F);
PointF pointf6 =new PointF(250F, 2 0 0 F ) ;
PointF pointf7 =new PointF(125F, 12 5 F ) ;
PointF [] ArrayOfPoints = {pointfl, pointf2, pointf3, pointf4,
pointf5, pointf6, pointf7};
Graphics Figures = t h i s .C reateGraphics();
Pen RedPen = new P e n ( Color.R e d ) ;
Pen GreenPen = new Pen(C o l o r .G r e e n ) ;
Pen BluePen = new Pen( C o l o r .B l u e ) ;
Brush YellowBrush = B r u s h e s .Yellow;
Brush OrangeBrush = B r u s h e s .O r a n g e ;
F i g u r e s .DrawRectangle(RedPen, 10, 10, 100, 100);
F i g u r e s .DrawEllipse(GreenPen, 25, 25, 50, 50);
F i g u r e s .DrawPolygon(BluePen, ArrayOfPoints);
F i g u r e s .FillPolygon(YellowBrush, A rrayOfPoints);
F i g u r e s .FillPie(OrangeBrush, 40, 150, 70, 70, 40, 50);
}
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 ());
}
}
}

D ia g o n a l lin e s c a n also b e c re a te d u s in g D ra w L in e , b u t if th e lin e is a s y m m e tric a l it


w ill a p p e a r c o a rse o r ja g g e d . I n G D I+, a so lu tio n k n o w n a s a n ti- a lia s in g is u se d . A n ti­
a lia s in g is a s m o o th in g te c h n iq u e , b a s e d on sh a d in g , w h ich is u s e d to re d u c e s h a rp n e s s .
To th e a r t i s t th is w o u ld m e a n in c lu d in g a so fte r sh a d e of th e lin e ’s color t h a t su rro u n d s th e
lin e; th u s , to th e p r o g ra m m e r th is w ill m e a n a d d in g a d d itio n a l lin es.

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};

Graphics Figures = t h i s .C r e a teGraphics();


Brush GreenBrush = B r u s h e s .Green;
Brush BlueBrush = B r u s h e s .A q u a ;
Brush BrownBrush = B r u s h e s .Brown;
Brush BurlyWoodBrush = B r u s h e s .Burl y W o o d ;
F i g u r e s .FillRectangle(BlueBrush, 0, 0, 300, 175);
F i g u r e s .FillRectangle(BurlyWoodBrush, 75, 90, 100, 85);
F i g u r e s .FillRectangle(BrownBrush, 90, 140, 20, 35);
F i g u r e s .FillRectangle(BrownBrush, 130, 130, 30, 30);
F i g u r e s .FillRectangle(GreenBrush, 0, 175, 300, 175);
F i g u r e s .FillPolygon(BrownBrush, A rrayOfPoints);
}
static void M a i n O {
Application.Run (new Forml ());
}
}
}

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

Font AlgerianFont = new F o n t ("Algerian", 10);


SolidBrush MyBrush = new SolidBrush(Color.F r o m A r g b (255, 0,
0 )) ;
t e s t .D r a w S t r i n g ("Salvatore A. B u o n o " ,
AlgerianFont, MyBrush, 60, 25);
}
static void M a i n O {
Application.Run(new F o r m l ());

AliceBlue DarkOliveGreen Indigo M ediumPurple Purple


AntiqueW hite DarkO range Ivory M edium SeaGreen Red
Aqua DarkOrchid K haki M ediumSlateBlue RosyBrown
A quam arine DarkRed Lavender M ediumSpringGreen RoyalBlue
Azure DarkSalmon LavenderBlush MediumTurquoise SaddleBrown
Beige D arkSeaG reen Law nG reen MediumVioletRed Salmon
Bisque D arkSlateBlue LemonChiffon MediumBlue SandyBrown
Black DarkSlateG ray LightBlue MintCream S eaG reen
BlanchedAlmond DarkTurquoise LightCoral MistyRose SeaShell
Blue DarkViolet LightCyan Moccasin Sienna
BlueViolet DeepPink LightYellow Nava jo White Silver
Brown DeepSkyBlue LightGray Navy SkyBlue
BurlyWood DimGray LightG reen OldLace SlateBlue
CadetBlue DodgerBlue LightPink Olive SlateG ray
C hartreuse Firebrick LightSalmon OliveDrab Snow
Chocolate FloralWhite LightSeaG reen O range SpringG reen
Coral ForestG reen LightSkyBlue OrangeRed SteelBlue
CornflowerBlue Fuchsia LightSlateGray Orchid Tan
Cornsilk Gainsboro LightSteelBlue PaleGoldenrod Teal
Crimson GhostW hite LightYellow PaleG reen Thistle
Cyan Gold Lime PaleTurquoise Tomato
DarkBlue Goldenrod Lim eG reen PaleVioletRed Turquoise
DarkCyan Gray Linen Papaya Whip Violet
DarkGoldenrod G reen M agenta Peachpuff W heat
D arkGray GreenYellow Maroon Peru White
D arkG reen Honeydew Med Aquamarine Pink W hiteSmoke
DarkKhaki HotPink MediumBlue Plum Yellow
DarkM agenta IndianRed MediumOrchid PowderBlue YellowGreen

T a b l e G .l . C o m p lete lis t of A K BG colors.

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

E a c h p la y e r b e g in s w ith six te e n c h a ra c te rs: one K ing, one Q ueen, tw o Rooks, tw o B ishops,


tw o K n ig h ts a n d e ig h t P a w n s. T h e p la y e rs a re lin e d u p on o p posite sid es of th e b o a rd w ith
th e lig h te r side p lacin g its rig h t-h a n d , or K ing-side Rook, on a lig h te r sq u a re . T he a r r a n g e ­
m e n t of th e k ey pieces is from left to r ig h t a n d is liste d as follows: Q u een -sid e Rook, Q ueen-
side K n ig h t, Q ueen -sid e B ishop, T he Q ueen, T he K ing, K ing-side B ishop, K ing-side K n ight,
a n d K ing-side Rook. T h e P a w n s a re th e n placed in th e sq u a re s d irectly in fro n t of th e m w ith
th e ir p o sitio n s d efin in g th e ir id e n titie s, i.e., Q ueen-R ook’s P a w n , Q u e e n -K n ig h t’s P aw n ,
Q ueen-B ishop’s P aw n, Q u een ’s P aw n, K ing’s P aw n, K ing-B ishop’s Paw n, K ing-K night P aw n,
K ing-R ook’s P a w n . T h e d a r k e r sid e m irro rs th e s e positio n s (see F ig u re H.2). N ote: T h e
Q u e e n ’s of e a c h side sh o u ld be lin e d u p v ertic ally w ith th e lig h te r Q u ee n p laced on a lig h te r
s q u a re a n d th e d a r k e r Q u e e n p laced on a d a r k e r sq u a re .

Figure
H.2.

E a c h p la y e r is o n ly a llo w ed one m ove p e r tu rn ; no tw o pieces m a y occupy th e sa m e


s q u a re a t a n y o ne tim e ; a n d a p la y e r c a n only c a p tu r e pieces form th e o p p o n e n t’s side.
O nce a piece is c a p tu re d , th e a tta c k in g piece ta k e s t h a t s q u a re a n d th e tu r n is co m ­
p le te . A t th e b e g in n in g of th e g am e, e a c h p la y e r is in s tr u c te d to se c re tly choose a piece
fro m th e ir o w n s e t of c h a r a c te r s w h ic h w ill re p r e s e n t th e m . T h e K in g is n o t c o n sid e re d
a v a lid choice, n o r a r e a n y of th e o p p o n e n t’s pieces; if a p la y e r fa ils to se lec t a v a lid
c h a ra c te r, h e a u to m a tic a lly fo rfe its th e gam e.
O nce th e g a m e is in play, it c a n only be te r m in a te d by one of six s itu a tio n s : 1) A
p la y e r ’s c h o se n p iece is c a p tu re d , w h ic h im m e d ia te ly e n d s th e g a m e giv in g th e w in to
th e p la y e r t h a t c a p tu r e d th e piece; 2) A K in g is p lac ed in c h e c k m a te , w h ic h also im m e ­
d ia te ly te r m in a te s th e g am e, b u t th is tim e it is co n sid ere d to be a d raw ; 3) A p la y e r c a n n o t

492
Appendix H: Algorithms

m ove a n y p ie c e w ith o u t p la c in g h is k in g in ch eck , w h ic h w o u ld c o u n t a s a d ra w ;


4) A p la y e r re s ig n s , fo rfe itin g th e g a m e , w ith th e w in going to th e r e m a in in g play er.
5) B o th p la y e rs a g re e to w ith d ra w (in th is case, th e p la y e r w ho w a s a h e a d w in s th e gam e).
6) A ll p la y e rs o n e ith e r sid e h a v e b e e n c a p tu re d ex ce p t for K in g a n d th e p la y e r ’s choice—
th e g a m e is th e n c o n sid e re d a v ic to ry for th e p la y e r w ith th e fe w e st pieces.

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.

If th e K in g is p la c e d in check, th e r e a re th re e p o te n tia l so lu tio n s: 1) H e c a n m ove to a n


a lte r n a tiv e sp ace, a s s u m in g th e r e is o ne t h a t is a v a ila b le t h a t d o e sn ’t b re a k th e ru le s
lis te d above; 2) H e o r a n o th e r sa m e -sid e piece c a n c a p tu re th e o p p o sin g piece, a s s u m in g
th is m ove c a n be done w ith o u t le a v in g th e K ing in a n y a d d itio n a l checks; a n d 3) I t m a y be
p o ssib le to block th e o p p o sin g p la y e r ’s lin e of a tta c k , by p la c in g a le s s e r piece b e tw e e n th e
K in g a n d h is o p p o n e n t. I t is a g a in s t th e r u le s to c a u se a check by m oving o n e’s ow n pieces
if th e y in a d v e rte n tly re v e a l a check. H ow ever, if a n o p p o n e n t c a n o pen a p a th by re m o v in g
one of h is ow n o b stacles, it w o u ld be c o n sid ere d legal, or w h a t is called a re v e a le d check. If
tw o o r m o re p iece a re th r e a te n in g th e K in g (a do u b le check) th is second choice w ill be

493
C# and Game Programming

n e g a te d . A lso, if th e K in g is u n a b le to relie v e a n y a n d /o r a ll c h eck s h e is c o n sid e re d to be


c h e c k m a te d a n d th e g a m e is te r m in a te d .
A k ey e x c e p tio n to th e K in g ’s o n e -ste p ru le is w h e n h e e x e rc ise s h is rig h t to castle.
C a s tlin g is a sp e c ia l m a n e u v e r w h e re in tw o pieces a re a c tu a lly d isp lace d . F ir s t, th e
K in g is allo w ed to ju m p tw o sp a c e s to e ith e r side, a n d th e a p p r o p ria te R ook is p la c e d on
th e o th e r sid e of h im . T h is m e a n s t h a t th e ro o k w ill lite ra lly ju m p o v er th e K in g (see
F ig u re s H .4 a n d H .5). T h e re a re s e v e ra l re s tr ic tio n s t h a t m a y in h ib it th e m a n e u v e r: 1)
T h is m u s t be th e K in g ’s f ir s t m ove; 2) A ll sp a c e s b e tw e e n th e R ook a n d th e K in g m u s t
be fre e of a n y pieces; a n d 3) T h e K in g m u s t n o t be in check, a n d h e m u s t n o t p a s s or
m ove o n to a s q u a re t h a t is c o n tro lle d by th e o p p o n e n t’s side.

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.

P a w n s also h o ld a sp e c ia l r ig h t to c a p tu re o th e r P a w n s. T h is sp e cia l c ase is k n o w n a s


th e “e n P a s s a n t,” b u t tw o c o n d itio n s m u s t be u p h e ld : 1) T h e c a p tu rin g P a w n m u s t be on
th e fifth r a n k (ra n k s c o u n te d from th e ir p la y e rs side); a n d 2) T h e o p p o n e n ts P a w n m u s t
e x e rc ise h is in itia l tw o -ste p op tio n . T h e a d ja c e n t P a w n c a n th e n ste p d ia g o n a lly o n to th e
u n o c c u p ie d s q u a re a n d ta k e th e o p p o n e n t’s P a w n . T h is sp ecial rig h t c a n o nly be e x e c u te d
im m e d ia te ly a fte r th e tw o -step ad v an ce. Also, if a P a w n re a c h e s th e o th e r e n d of th e b o ard ,

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).

cdtinn3 - Microsoft Visual O .NET [design] • Forni1.cs* E B B


• WindowsAppl
Fie Ed* flew Project ] 0uld Qebug Ioob Window' Help
Add Windows Eprm... j Debug * ^ catch *. a a r r
Add Inherited Form.
m % &= *
j| Add User Control... < T x l Solution Explorer... X
[ s ta r t Page j Fount
'•2 Add Inherited Control...
j^fWndowsApplcat [jj¥Forml_Load(object sender,System.EventArgs e) J*j !
S i Add Component j elution 'WindowsApphcation3'
5 ................... * ]3 WindowsApplication3
Af Add Class...
i References
fv§ Add Ness Item... Ctrl+5h#t+A K > );
; S App.ico
iyfjj AddExistiriQItem... Shft+A*+A *J AssemblyInfo.es
| 9 Forml.cs
| Exclude From Project : t s e n d e r , S y s te m .E v e n tA r g s e)
j§! Shfiw AIFIes

Screen [ Add Reference...


- > Add Wgb Reference
Shot 1.1 -
Set as Startup Project

.. I < >

Output * X

(3 Task List 1 ) Output] Secrth Results for Dr

■ £ Chspt«*.dnc- Micro...

S t e p 2. A s th e “A d d R e fe re n c e ” p o p u p w indow a p p e a rs , sim p ly scroll dow n, n o tin g th e


listings“M icrosoft.DirectX,”‘M icrosoft.D irectX .D irectD raw ,” “M icrosoft.D irectX .D reictInput,”
a n d M ic ro so ft.D ire c tX .D irec tS o u n d .” D ouble click on a ll fo u r of th e s e e n tr ie s a n d th e n
p re s s “O K ” (see S c re e n S h o t 1.2).

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.,.

S t e p 3. Now, in o rd e r to u s e th e s e lin k s, y o u ’ll h a v e to in c lu d e a s e t of “u s in g ” s t a t e ­


m e n ts , a s i n “u s in g M ic ro s o ft.D ire c tX ,” “u s in g M ic ro s o ft.D ire c tX .D ire c tD ra w ,“u s in g
MicmsoftJ)irectXDirectSound,’’‘hsingBufifei^ M icrosoft. D irectX .D irectS ound. S econdaryB uffer,”
a n d “u s in g M ic ro s o ft.D ire c tX .D ire c tln p u t.”

500
Index

Symbols 178, 1 9 6 ­ saving and retrieving data


199, 2 80, 2 8 6 2 8 7 -2 8 8
.net design xviii as 25, 3 8 4 ­ setting levels 2 8 7
.net fram ework 5 3 86 , 4 3 7 , 4 3 9 , 4 7 5 weapons 2 8 8 - 2 8 9
Assembly Language 9 binary scope resolution
A
Asteroid M iner 2 0 4 ­ operator 3 2 8 - 3 3 3
abstract 25, 371 - 205, 2 0 8 bool 25, 9 0 - 9 1 , 4 37, 4 4 0
3 74, 399, 4 37 , 4 3 9 brainstorming 2 0 4 - 2 0 5 boxing 1 0 0 -1 0 1 , 4 5 7
access modifier 4 6 ­ GDI+ graphics 2 0 5 break 25, 7 6 - 7 7 , 8 6 ­
48, 3 3 3 -3 3 5 , 3 9 3 ­ AT&T Bell Laboratories 4 88, 4 37 , 4 4 0
395, 4 5 4 byte 25, 28, 4 37 , 441
B
addition 38
Algol 6 0 4
c
base 25, 3 7 5 ­
algorithm xxi, 7 -8 , 1 3 9 ­ 3 76 , 3 86 , 4 3 7 , 4 3 9 C /C + + history 4
142, 183, 491 BASIC 3, 8 Caesar, Augustus 2 1 5
AMD xviii, xxiii Battle Bit 7 7 - 8 0 call-by-mechanism
American National Standards Battle Tennis 2 8 9 - 3 0 4 224, 3 1 9 -3 2 1
Institute [ANSI] 4 adding graphics 2 9 0 - 2 9 5 call-by-reference 103, 1 12 —
and 6 8 - 6 9 brainstorming 2 8 9 - 2 9 0 114, 2 40 , 2 4 4 ­
animation 4 0 3 - 4 0 4 changing levels 3 0 3 - 3 0 4 246, 3 1 6 -3 2 1
Apple-Macintosh xviii input devices 2 9 5 - 2 9 7 call-by-value 103, 1 0 8 ­
arithm etic 3 8 - 4 3 , 7 1 - 7 3 Battle Wave 2 6 9 - 2 8 9 110, 1 1 2 - 1 1 4
array 216, 2 1 7 - 2 3 7 algorithm fo r 2 7 2 - 2 7 3 Camel notation 102
assigning values 2 2 0 -2 2 1 animation 2 8 0 - 2 8 2 case 25, 8 5 ­
call-by-reference 2 2 2 - 2 2 5 artificial intelligence 2 8 6 88, 4 3 7 , 441
declaring and referencing brainstorming 2 7 0 catch 25, 3 7 6 ­
2 1 7 -2 2 0 character limits 2 8 2 - 2 8 3 377, 4 37 , 4 4 1 - 4 4 2
dynamic 2 3 5 - 2 3 7 characters and motions CD-ROM xix, xxiii, 3 07
multidimensional 2 2 5 ­ 271 char 25, 3 1 - 3 2 , 9 4 ­
227, 2 2 8 - 2 3 2 drawinq characters 2 7 3 ­ 98, 4 37, 4 4 2
passing 222, 2 2 3 - 2 2 5 274 checked 25, 2 6 6 ­
searching 2 3 2 - 2 3 5 joystick 2 8 4 - 2 8 5 2 68, 4 3 7 , 4 4 2 , 4 7 5
artificial intelligence keyboard 2 8 3 - 2 8 4 cin 8 8 - 9 0 , 261
xix, 96, 1 7 6 - rendered designs 2 7 7 class 25, 4 37 , 4 4 3

501
C# and Game Programming

classes 3 2 4 -3 4 4 , 3 5 2 ­ default 25, 8 5 ­ extern 25, 2 6 0 -2 6 1 , 3 8 8 ­


354 88, 4 3 7 , 4 4 4 3 89 , 4 3 7 , 4 4 8
arrays 3 3 5 - 3 3 6 delegate 25, 3 8 5 ­
assigning instances 3 4 3 ­ 387, 437, 4 4 4 - 4 4 5 F
344 Delphi 5
false 25, 91, 4 37 , 4 4 8
constructors 3 4 0 Direct3D 4 2 9 -4 3 1
fields
destructors 3 4 9 - 3 5 0 DirectDraw 1 4 4 ­
private 3 2 8 - 3 3 3
internal access modifier 145, 194, 4 3 0 , 4 9 9
protected 3 2 8 - 3 3 3
3 3 3 -3 3 5 Directlnput 1 4 9 -1 5 0 , 1 6 9 ­
finally 25, 3 7 6 ­
overloading 3 3 6 - 3 3 7 171
377, 4 3 7 , 4 4 8 - 4 4 9
overloading constructors joystick 1 6 9 -1 7 1 , 2 1 0
fixed 25, 3 9 0 ­
3 42 keyboard 1 8 8 -1 8 9 , 2 1 0
3 91 , 4 3 7 , 4 4 9
private 3 2 4 DirectSound 1 6 2 ­
float 25, 2 8 ­
private and protected 164, 211, 2 97 , 2 9 9 ­
30, 4 37 , 4 4 9 - 4 5 0
3 2 8 -3 3 3 , 3 3 8 - 3 4 0 304
for 25, 8 3 - 8 5 , 4 3 7 , 4 5 0
protected 3 2 4 division 4 0 - 4 1
force feedback 2 8 4 - 2 8 5
public 324, 3 2 5 - 3 2 8 do 25, 8 1 - 8 3 , 4 37 , 4 4 5
foreach 25, 2 3 7 ­
collision detection 4 0 5 - 4 0 8 double 25, 2 8 ­
238, 242, 4 37 , 4 5 0 ­
colors 160, 4 8 9 30, 4 3 7 , 4 4 5
451
comments 1 5 - 1 6 Dr. Dobb's Journal 5
form atting strings 3 7 - 3 8
Common Language Runtime
E FORTRAN 3
5
compound if 6 6 - 6 7 G
Einstein, Albert 3
conditional operator 9 2 - 9 3
else 25, 6 3 - 6 4 , 4 3 7 , 4 4 6
cons 4 6 - 4 8 garbage collection
else-if 6 4 - 6 5
Console.Write 16 5, 3 9 0 , 4 0 0 , 4 6 3
enum 25, 2 3 8 ­
Console.Writeline 2 0 get 391 - 3 9 3 , 4 7 3
239, 4 37 , 4 4 6
const 25, 4 37 , 4 4 3 goto 25, 2 6 8 ­
European Computer Manu­
continue 25, 77, 437, 4 4 3 269, 4 37 , 4 5 1 - 4 5 2
facturers' Association
cout 8 8 - 9 0 Ground Assault 431
xvii, 4
Cyrix xviii brainstorming 431
event 25, 3 8 6 ­
graphics 4 3 2
3 87 , 4 3 7 , 4 4 7
D exception handling 3 7 6 - 3 7 7 H
decimal 25, 30, 4 37 , 4 4 4 exceptions
classes 3 8 0 - 3 8 4 heap
declaring variables 2 6 ­
explicit 25, 389, 4 37, 4 4 7 112 215 235 341, 353 4 D
28, 50
explicit conversions 9 9 - 1 0 0 Hejlsberg, Anders 4
decrementing operators 4 8 ­
Extended Markup Language Hewlett-Packard 4
49, 75, 149, 2 4 7 ­
(XML) 16 Hungarian notation 2 4 ­
2 48
25, 52, 102

502
Index

I long 25, 28, 4 37 , 4 5 5 ­ statements 7 0


456 structures 3 1 6
if 25, 5 9 - 6 7 , 4 3 7 , 4 5 1 ­ loops try blocks 3 7 8 - 3 7 9
452 nested 8 7 - 8 8 new 25, 236, 437, 4 5 6 ­
if-else 6 3 - 6 4 4 57 , 4 7 5
implicit 25, 3 90 , 4 3 7 , 4 5 2 M new, 4 7 5
implicit conversion 3 6 newline 1 8 - 2 0
Machine Language 8
in 25, 4 37, 4 5 2 not 6 8 - 6 9
Malloc 2 6 5
incrementing operator 4 8 ­ null 25, 244, 4 37 , 4 5 7
Managed C++ 4, 3 5 3
49
mean 2 5 4 - 2 5 6 □
Indenting 23
median 2 5 4 - 2 5 6
inheritance 3 24, 3 5 9 - 3 6 6
member selection operator object 25, 4 37 , 4 5 7
inline functions 1 19
3 1 0 -3 1 3 , 3 2 8 object-oriented programming
int 25, 2 6 - 2 8 , 4 3 7 , 4 5 3
memberwise copy 3 4 3 - 3 4 4 xxi, xxii, 146, 324, 359,
Intel xxiii
menus 171 - 1 7 6 385 , 4 3 5
interface 25, 3 9 3 ­
metafiles 4 0 0 operators 25, 3 5 4 ­
3 95, 4 3 7 , 4 5 3 - 4 5 4
methods 3 2 8 355, 4 37 , 4 5 8
internal 25, 3 3 3 -3 3 5 , 4 5 4
metonym data types 5 0 -5 1 nesting 3 5 6 - 3 5 7
Interntional Standards
Michelangelo 129 overloading 3 5 0 - 3 5 5
Organization [ISO] 4
Microsoft's Intermediate unary 3 5 8 - 3 5 9
intersects 4 0 5
Language (MSIL) 5 or 6 8 - 6 9
is 25, 396, 4 3 7 , 4 5 4 ­
mode 2 5 4 - 2 5 6 order of precedence 4 7 5
455, 4 75
Modula-2 3 out 25, 1 1 4 ­
J mom entum 115, 4 3 7 , 4 5 8
180, 183, 184, 2 0 0 overloading 1 1 5 -1 1 7
Java 5 multiplication 4 0 comparison operators
JIT 5, 9 3 5 4 -3 5 5
N constructors 3 4 2
K member function 3 3 6 ­
namespace 25, 5 1 ­
Keller, Helen 59 3 37
52, 4 3 7 , 4 5 6
keyword defaults 5 0 -5 1 override 25, 3 6 6 ­
naming variables 2 3 - 2 6
371, 4 3 7 , 4 5 9
Native C++
L
6, 14, 143, 2 37, 2 4 2 P
Lee, Meng 4 native C++ 341
Linux xviii nested 7 0 PaddleTennis 1 3 2 - 1 7 9
Lisp 3 class 351, 356, 3 9 2 ­ adding files 1 4 6 -1 4 8
lock 25, 3 9 7 ­ 393, 4 3 5 algorithm 1 3 9 -1 4 2
398, 4 3 7 , 4 5 5 classes 3 6 2 artificial intelligence 17 6 ­
Logo 3 exceptions 3 8 2 - 3 8 4 178
loops 8 2 - 8 3 , 228, 2 6 9 brainstorming 1 3 2 -1 3 3

503
C# and Game Programming

collision detection 1 5 1 ­ 25, 4 3 7 , 4 6 0 , 4 6 0 ­ short 25, 28, 4 37 , 4 6 3


152, 1 5 2 -1 5 4 , 1 5 4 ­ 461 short circuit evaluation 9 1 ­
155 members 3 3 8 - 3 4 0 92
colors 160 private and protected 3 3 8 ­ Simula67 4
details 1 5 6 -1 5 9 340 sizeof 25, 33, 4 37 , 4 6 3
DirectDraw 1 4 4 -1 4 5 reading and writing 3 4 4 Software Development Kit
drawing characters 1 3 3 ­ protected 25, 4 37 , 4 6 0 ­ (SDK) 130, 209, 4 2 9
138 461 sorting 231 - 2 3 2
game controls 1 5 7 - 1 5 9 members 3 3 8 - 3 4 0 sound 1 6 1 -1 6 2 , 2 9 9 - 3 0 0
joystick 1 6 9 -1 7 1 public 25, 3 2 5 ­ properties of 2 9 7
keyboard 1 4 9 - 1 5 0 3 28 , 4 37, 4 6 0 -4 6 1 three-dimensional 2 9 9 ­
menus 1 7 1 -1 7 6 300
mouse 1 6 4 -1 6 7 , 1 6 8 ­ Q sound effects 3 0 0 - 3 0 2
169 Space Fighters 1 8 1 - 2 0 4
questions 5 7 - 5 8 , 1 2 3 ­
multimedia 1 6 1 -1 6 2 algorithm 1 8 3 -1 8 5
124, 213, 3 0 6 ­
plotting motions 1 3 8 -1 3 9 artificial intelligence 19 6 ­
3 07 , 4 3 5
residual images 1 5 0 -1 5 1 199
sound 1 6 1 -1 6 2 , 1 6 2 ­ R brainstorming 1 8 0 -1 8 1
164 characters and motion
params range 2 5 4 - 2 5 6 1 8 1 -1 8 3
25, 3 98 , 4 3 7 , 4 5 9 ­ Rat Racer 432, 4 3 2 - 4 3 3 compiler 185
460 , 4 6 0 adding animation 4 3 2 ­ DirectDraw 1 94
Pascal 3, 5 433 hyperspace 1 9 0 -1 9 1
Pascal notation 24, 52 brainstorming 4 3 2 limits 1 9 1 -1 9 3
passing variables readonly 25, 4 37 , 461 menus 2 0 2 - 2 0 3
103, 108, 1 1 2 - 1 1 4 recursion 118 momentum 2 0 0
pointer 2 3 9 -2 4 0 , 2 4 0 ­ ref 25, 1 1 2 ­ obstacles 1 9 9 ­
241, 2 4 2 -2 4 4 , 2 4 4 ­ 114, 4 3 7 , 461 200, 2 0 1 - 2 0 2
246, 2 4 6 -2 4 8 , 2 4 8 ­ reserved indentifiers OnPaint 1 8 9 - 1 9 0
252, 2 5 2 -2 5 4 , 2 5 4 ­ 4 37 , 4 3 9 stackalloc 25, 2 5 6 ­
256, 2 5 6 -2 5 7 , 2 5 8 ­ return 25, 1 0 5 ­ 257, 4 0 0 , 4 3 7 , 4 6 3
259, 2 5 9 - 2 6 0 108, 4 3 7 , 4 6 2 Standard Template Libary 4
pointer arithmetic 2 4 6 - 2 4 8 static 25, 2 6 0 ­
S
polymorphism 59, I I S - 261, 3 25, 4 37 , 4 6 4
117, 3 5 9 sbyte 25, 28, 437, 4 6 2 Stepanov, Alexander 4
predefined functions 9 3 - 9 8 scanf 8 8 - 9 0 , 148 storage class specifiers 2 6 0 ­
preprocessor directives sealed 25, 399, 4 3 7 , 4 6 2 261
22, 3 8 7 - 3 8 8 semicolon string 25, 3 1 ­
printf 8 8 - 9 0 22 25 iaQ 31Q 388, 465 32, 4 3 7 , 4 6 4
private set 3 9 1 -3 9 3 , 4 7 3 Stroustrup, Bjame 4

504
Index

stru ct 25, 310, 4 3 7 , 4 6 4 ­ throw 25, 3 7 9 ­ user-defined functions 101


465 3 80 , 4 3 7 , 4 6 6 ushort 25, 28, 4 37, 4 6 9
structures troubleshooting 5 3 ­ using 25, 5 1 ­
arrays of 3 0 9 - 3 2 4 56, 1 1 9 -1 2 1 , 2 0 9 ­ 52, 4 37 , 4 6 9 - 4 7 0
complex 3 1 5 - 3 1 6 2 12 , 3 0 4 -3 0 5 , 4 3 5 utils.cs 4 2 5 - 4 2 7
fields 3 1 0 - 3 1 3 true 25, 91, 4 37 , 4 6 6 V
instances of 3 0 9 - - 3 1 3 try 25, 3 7 8 ­
mechanism with 3 1 6 - 3 1 7 379, 437, 4 6 6 -4 6 7 value 4 7 3
methods 3 2 8 Turbo Pascal 5 variable scope 1 0 3 - 1 0 5
passing 3 1 9 -3 2 1 type virtual 25, 3 6 6 ­
private 3 2 8 casting 9 9 - 1 0 0 , 4 5 7 371, 4 3 7 , 4 6 9 - 4 7 0
protected 3 2 8 compatibility 2 9 8 Visual Basic 2 3 7
public 325, 3 2 8 computability 3 6 - 3 7 void 25, 35, 4 3 7 , 4 7 0
reference 3 1 8 - 3 1 9 safety 9, 49, 3 8 5 void pointer 2 42 , 2 5 2 - 2 5 4
reference mechanism with typedef 5 0 -5 1 volatile 25, 4 6 ­
3 1 9 -3 2 1 typeof 25, 4 37, 4 67 , 4 7 5 48, 4 3 7 , 4 7 0
storing and retrieving
W
3 2 1 -3 2 4 U
tag 3 1 0 while 25, 7 3 ­
subtraction 3 9 uint 28, 4 3 7 , 4 6 7 77, 4 3 7 , 471
switch 25, 8 5 ­ ulong 25, 28, 4 37 , 4 6 8 W indows API 5, 33
88, 4 37 , 4 6 5 unboxing 1 0 0 -1 0 1 , 4 5 7 W riteLine 2 0 - 2 2
system requirements xxiii unchecked 25, 2 6 6 ­
system.lO 2 6 5 - 2 6 6 2 68, 4 3 7 , 4 6 8 ­ X
469, 475
XML 16
unit 2 5
UNIX xviii Z
this 25, 3 4 4 ­ unsafe 25, 33, 2 4 0 ­
3 49 , 4 37 , 4 6 5 - 4 6 6 2 41 , 4 3 7 ,4 6 8 - 4 6 9 zero-impact installation 5

505

Você também pode gostar