<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9</title>
      <link>http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts</link>
    <language>en</language>
    <pubDate>Mon, 20 May 2013 14:47:57 GMT</pubDate>
    <lastBuildDate>Mon, 20 May 2013 14:47:57 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>10</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Beginning Game Development Part X –Direct Sound Part III</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">Welcome to the tenth article on beginning game development. In the last article we manipulated sounds by adding sound effects. Together with the use of 3D Buffers to make the sounds positionaly accurate we now have
 a fully featured sound system in the game. But, while we're are able to play and manipulate short sounds and sound effects we cannot play longer WMA or MP3 files with the DirectSound namespace. To accomplish that we need to turn to the AudioVideoPlayback namespace.
</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input">Visual Studio Express 2005, Microsoft DirectX SDK</span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">Any PC capable of running DirectX 9.0</span></div>
<div class="entry_details"><b>Download: </b><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=370370">Download</a>
</div>
<p>Previous Articles:</p>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
<h4>Why more sound </h4>
<p>You may be wondering why we even need to add longer sound files to the game. As I mentioned in article 8, most games include fully featured soundtracks in addition to the regular game sounds. These sound tracks are often produced specifically for the game
 much like a movie soundtrack is produced for a movie. A well made sound track can add additional drama to the game and provide a memorable experience. Sometimes these game tracks are also available as separate music CDs or downloads to bring more players to
 the game. There is really no way that anyone is going to be able to produce a nice sounding soundtrack as a WAV file. Most music uses the MP3 codec or can be converted to this codec.
</p>
<h4>Audio Playback</h4>
<p>Using the DirectSound namespace we were only able to play WAV files. Longer music is normally encoded in more efficient formats such as MP3 or WMA. To play these files we have to access the API in the AudioVideoPlayback namespace. This namespace is the smallest
 of the namespaces and contains a single class called Audio for playing audio files. (It also contains a Video class which I will not cover)
</p>
<p>Using the Audio class to play an audio file is very easy. </p>
<p>1. Create a new Audio class and pass the path to the Audio file to the constructor.
</p>
<div>
<div>
<pre>Audio audio = <span>new</span> Audio(<span>&quot;AudioFileName&quot;</span>);</pre>
</div>
Or instantiate a new Audio class and then call the Open method.</div>
<div>&nbsp;</div>
</td>
</tr>
</tbody>
</table>
</span>
<div>
<div>
<pre>Audio audio = <span>new</span> Audio();</pre>
<pre>audio.Open(<span>&quot;AudioFileName&quot;</span>);</pre>
</div>
2. Call the Play method.</div>
<div>&nbsp;</div>
<div>
<div>
<pre>audio.Play();</pre>
</div>
3. While playing an audio file you can pause it and then resume it by calling pause and then play.</div>
<div>&nbsp;</div>
<div>
<div>
<pre>audio.Pause();</pre>
</div>
4. When you are done playing the file just call the Stop method.</div>
<div>&nbsp;</div>
<div>
<div>
<pre>audio.Stop();</pre>
</div>
5. Finally remember to dispose the Audio Object.</div>
<div>&nbsp;</div>
<div>
<div>
<pre>audio.Dispose();</pre>
</div>
There is no looping built into the Audio class, but the class exposes an Ending Event that we can hook into the loop the audio.</div>
<div>&nbsp;</div>
<div>
<div>
<pre><span>private</span> <span>void</span> _audio_Ending(<span>object</span> sender, EventArgs e)</pre>
<pre>{</pre>
<pre>    audio.Play();</pre>
<pre>}</pre>
</div>
Another neat feature of the Audio class is the ability to open an audio file from an URI rather than a file name. This allows you play audio files from the Internet or URL addressable location.</div>
<div>&nbsp;</div>
<div>
<div>
<pre>audio.Open(<span>&quot;//www.audiofile.com/music.mp3&quot;</span>);</pre>
</div>
</div>
<p>While playing the audio file you can control the volume and balance of the file.
</p>
<p><b>Volume</b>: Volume is expressed as an integer. Somewhat counterintuitive is that a setting of 0 is full volume. Smaller values decrease the volume up to a setting of -10,000 which is silent.
</p>
<div>
<div>
<pre>audio.Volume = 0; <span>// Maximum</span></pre>
<pre>audio.Volume = -10000; <span>// Silent</span></pre>
</div>
<b>Balance</b>: Balance is expressed as an integer in the range of 10,000 to -10,000. A value of zero means that the sound is perfectly balanced, while -10,000 plays only the left channel and, you guessed it, 10,000 plays on the right.</div>
<div>&nbsp;</div>
<div>
<div>
<pre>audio.Balance = -10000; <span>// Only Left channel</span></pre>
<pre>audio.Balance = 10000; <span>// only Right channel</span></pre>
<pre>audio.Balance = 0; <span>// balanced</span></pre>
</div>
For each of the methods representing the major states of the class the Audio class raises events to indicate these states and exposes properties to check what state the class is in. You already saw the Ending event. This matrix shows the major states, methods
 to get the class into the state, event raised when entering the state and properties that can be used to detect the state.
</div>
<p>
<table class="" width="469" border="1">
<thead>
<tr>
<th class="" width="71">State</th>
<th class="" width="178">Method</th>
<th class="" width="59">Event</th>
<th class="" width="146">Property (Boolean)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="" width="71">Started</td>
<td class="" width="178">Play</td>
<td class="" width="61">Starting</td>
<td class="" width="145">Playing*</td>
</tr>
<tr>
<td class="" width="71">Paused</td>
<td class="" width="178">Pause</td>
<td class="" width="63">Pausing</td>
<td class="" width="144">Paused</td>
</tr>
<tr>
<td class="" width="71">Stopped</td>
<td class="" width="178">Stop and StopWhenReady</td>
<td class="" width="64">Stopping</td>
<td class="" width="144">Stopped**</td>
</tr>
<tr>
<td class="" width="71">Ended</td>
<td class="" width="178">N/A</td>
<td class="" width="65">Ending</td>
<td class="" width="146"></td>
</tr>
</tbody>
</table>
</p>
<p><i>* While playing the audio class indicates the current position of the stream with the
<b>CurrentPosition</b> property.</i> </p>
<p><i>** The audio class also provides a property, <b>StopPosition</b>, which indicates the position in the audio stream where the file is stopped</i>
</p>
<p>You can also use the <b>State </b>property of the <b>Audio </b>class to determine its state. This property returns a
<b>StateFlags </b>enumeration with the possible values of: <b>Running</b>, <b>Paused</b> and
<b>Stopped</b>.<br>
Also of interest is the <b>SeekingCaps </b>property of the <b>Audio </b>class. This read only property indicates the seeking capabilities of the playback stream. It is represented in the form of the
<b>SeekingCaps </b>structure. This structure indicates whether the stream supports the following seek actions:<i></i>
</p>
<p>
<table class="" width="430" border="1">
<thead>
<tr>
<th class="" width="146">Action</th>
<th class="" width="276">SeekingCaps property (Boolean)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="" width="146">Current position</td>
<td class="" width="276">CanGetCurrentPostion</td>
</tr>
<tr>
<td class="" width="146">Duration</td>
<td class="" width="276">CanGetDuration</td>
</tr>
<tr>
<td class="" width="146">Stop position</td>
<td class="" width="276">CanGetStopPostition</td>
</tr>
<tr>
<td class="" width="146">Absolute</td>
<td class="" width="276">CanSeekAbsolute</td>
</tr>
<tr>
<td class="" width="146">Seek Forwards</td>
<td class="" width="276">CanSeekForward</td>
</tr>
<tr>
<td class="" width="146">Seek Backward</td>
<td class="" width="276">CanSeekBackward</td>
</tr>
</tbody>
</table>
</p>
<p>You should check the capabilities of the stream before calling <b>SeekCurrentPosition, SeekStopPosition
</b>or checking the <b>Duration </b>property. </p>
<p>Ok, let's package this simple class into a Jukebox. I want the Jukebox class to pull files from a predetermined location so I can just point it at a media folder within the games directory structure. I also want the Jukebox to either play all the files it
 finds in order or play a single file in a looping fashion. </p>
<p>Finally I want this class to play a specific file on demand, for example, when I am on the splash screen I want to play the intro tune, while on the main game screen I want some other background music.
</p>
<p><b>NOTE</b>: I am not providing any audio files with the source code. By default the SoundTrack class reads from C:\Documents and Settings\All Users\Documents\My Music\Sample Music where you should have two WMA files on a standard XP machine. If you do not
 have those files you need to change the directory and point it at a location that has sound files.
</p>
<h4>Creating the SoundTrack class</h4>
<p>The first step is to add a reference to the <b>Microsoft.DirectX.AudioVideoPlayback</b> assembly.<br>
Next we add a new class and call it <b>Soundtrack</b>. At the top of the class we need add the using statement for the
<b>AudioVideoPlayback</b> namespace. </p>
<div>
<div>
<pre><span>using</span> Microsoft.DirectX.AudioVideoPlayback;</pre>
</div>
Like all the other classes we are going to implement the <b>IDisposable</b> interface to ensure proper resource management.</div>
<div>&nbsp;</div>
<div>
<div>
<pre><span>public</span> <span>void</span> Dispose()</pre>
<pre>{</pre>
<pre>    Dispose(<span>true</span>);</pre>
<pre>    GC.SuppressFinalize(<span>this</span>);</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>protected</span> <span>virtual</span> <span>void</span> Dispose(<span>bool</span> disposing)</pre>
<pre>{</pre>
<pre>    <span>if</span> (!<span>this</span>._disposed)</pre>
<pre>    {</pre>
<pre>        <span>if</span> (disposing)</pre>
<pre>        {</pre>
<pre>            <span>if</span> (_audio != <span>null</span>)</pre>
<pre>            _audio.Dispose();</pre>
<pre>        }</pre>
<pre>    }</pre>
<pre>    _disposed = <span>true</span>;</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>// Use C# destructor syntax for finalization code.</span></pre>
<pre>~SoundTrack()</pre>
<pre>{</pre>
<pre>    <span>// Simply call Dispose(false).</span></pre>
<pre>    Dispose(<span>false</span>);</pre>
<pre>}</pre>
<pre>&nbsp;</pre>
<pre><span>private</span> <span>bool</span> _disposed;</pre>
</div>
The constructor of the class will receive an array of file names and an indicator if we want to play the files in a loop.</div>
<div>&nbsp;</div>
<div>
<div>
<pre><span>public</span> SoundTrack ( <span>string</span>[] songCollection, <span>bool</span> repeat )</pre>
<pre>{</pre>
<pre>    _songList = songCollection;</pre>
<pre>    _isRepeat = repeat;</pre>
<pre>    </pre>
<pre>    <span>if</span> ( _songList.Length == 0 )</pre>
<pre>        _enabled = <span>false</span>;</pre>
<pre>    <span>else</span></pre>
<pre>        _audio = <span>new</span> Audio ( _songList[ _songCounter ].ToString ( ) );</pre>
<pre>}</pre>
</div>
Next we declare a number of private properties for the class to hold the songs, and counter information.</div>
<div>&nbsp;</div>
<div>
<div>
<pre><span>private</span> Audio _audio;</pre>
<pre><span>private</span> <span>string</span>[] _songList;</pre>
<pre><span>private</span> <span>int</span> _songCounter = 0;</pre>
<pre><span>private</span> <span>bool</span> _isRepeat;</pre>
<pre><span>private</span> <span>bool</span> _enabled = <span>true</span>;</pre>
</div>
</div>
<div>Now we add the Play method to the class<b>.</b></div>
<div><strong></strong>&nbsp;</div>
<div>
<div>
<pre><span>public</span> <span>void</span> Play()</pre>
<pre>{</pre>
<pre>    <span>if</span> ( !_enabled )</pre>
<pre>        <span>return</span>;</pre>
<pre>    </pre>
<pre>    _audio.Play();</pre>
<pre>    _audio.Ending &#43;= <span>new</span> EventHandler(_audio_Ending);</pre>
<pre>}</pre>
</div>
All we have to do is to call the Play method of the Audio class. Finally we need to hook the Ending event to implement the looping capabilities.</div>
<div>&nbsp;</div>
<div>
<div>
<pre><span>private</span> <span>void</span> _audio_Ending(<span>object</span> sender, EventArgs e)</pre>
<pre>{</pre>
<pre>    <span>if</span> ( _isRepeat )</pre>
<pre>    {</pre>
<pre>        Stop ( );</pre>
<pre>        Play ( );</pre>
<pre>    }</pre>
<pre>    <span>else</span></pre>
<pre>        NextSong ( );</pre>
<pre>}</pre>
</div>
This method simply calls the NextSong method if we are not repeating the song, or stops and plays the same song again.</div>
<div>&nbsp;</div>
<div>
<div>
<pre><span>public</span> <span>void</span> NextSong ( )</pre>
<pre>{</pre>
<pre>    <span>if</span> ( !_enabled )</pre>
<pre>        <span>return</span>;</pre>
<pre>    </pre>
<pre>    _songCounter&#43;&#43;;</pre>
<pre>    </pre>
<pre>    <span>if</span> ( _songCounter == _songList.Length )</pre>
<pre>        _songCounter = 0;</pre>
<pre>    </pre>
<pre>    <span>if</span> ( _audio.Playing == <span>true</span> )</pre>
<pre>        _audio.Stop ( );</pre>
<pre>    </pre>
<pre>    _audio.Open ( _songList[ _songCounter ].ToString ( ) );</pre>
<pre>    _audio.Play ( );</pre>
<pre>}</pre>
</div>
Here we simply increment the counter to the next song, pass that song to the Audio class and play the song.</div>
<p>The only remaining method we now need is to stop the player </p>
<div>
<div>
<pre><span>public</span> <span>void</span> Stop ( )</pre>
<pre>{</pre>
<pre>    <span>if</span> ( !_enabled )</pre>
<pre>        <span>return</span>;</pre>
<pre>    </pre>
<pre>    <span>if</span> ( _audio != <span>null</span> )</pre>
<pre>        _audio.Stop ( );</pre>
<pre>}</pre>
</div>
</div>
<p>To allow us to control the balance and volume we simply add two properties to the SoundTrack class that expose the identical properties of the Audio class. Since we know the upper and lower bounds of the values, we add a simple check to the property setter
 to ensure we only pass valid values. This is more efficient than passing an invalid value and having to check for exceptions. In general you should enforce boundaries whenever possible.</p>
<div>
<div>
<pre><span>   1:</span> <span>public</span> <span>int</span> Volume</pre>
<pre><span>   2:</span> {</pre>
<pre><span>   3:</span>     get { <span>return</span> _audio.Volume; }</pre>
<pre><span>   4:</span>     set </pre>
<pre><span>   5:</span>     {</pre>
<pre><span>   6:</span>         <span>if</span> ( <span>value</span> &gt; 0 | <span>value</span> &lt; -10000 )</pre>
<pre><span>   7:</span>             <span>return</span>;</pre>
<pre><span>   8:</span>         </pre>
<pre><span>   9:</span>         _audio.Volume = <span>value</span>; </pre>
<pre><span>  10:</span>     }</pre>
<pre><span>  11:</span> }</pre>
<pre><span>  12:</span>&nbsp; </pre>
<pre><span>  13:</span> <span>public</span> <span>int</span> Balance</pre>
<pre><span>  14:</span> {</pre>
<pre><span>  15:</span>     get { <span>return</span> _audio.Balance; }</pre>
<pre><span>  16:</span>     set </pre>
<pre><span>  17:</span>     {</pre>
<pre><span>  18:</span>         <span>if</span> ( <span>value</span> &gt; 10000 | <span>value</span> &lt; -10000 )</pre>
<pre><span>  19:</span>             <span>return</span>;</pre>
<pre><span>  20:</span>         </pre>
<pre><span>  21:</span>         _audio.Balance = <span>value</span>; </pre>
<pre><span>  22:</span>     }</pre>
<pre><span>  23:</span> }</pre>
</div>
</div>
<p>Now we can integrate the new class into the game. First we add a reference to the new class to the
<b>GameEngine</b> class. </p>
<div>
<div>
<pre><span>private</span> SoundTrack _mainSoundTrack;</pre>
</div>
Now we initialize the new class in the <b>ConfigureSounds</b> method of the <b>GameEngine</b> class.</div>
<div>&nbsp;</div>
<div>
<div>
<pre>_mainSoundTrack = <span>new</span> SoundTrack ( Directory.GetFiles ( <span>@&quot;C:\Documents&quot;</span> &#43; </pre>
<pre>    <span>&quot;and Settings\All Users\Documents\My Music\Sample Music&quot;</span> ), <span>true</span> );</pre>
</div>
To control the sounds for experimental purpose only, we are going to associate a number of keyboard keys with the Play, Stop and Next methods of the class. In a real game we would only expose a mute function, while the sound settings for volume and balance
 would be part of the game options screen. The actual playing of the various sounds would be controlled by the state of the game.</div>
<div>&nbsp;</div>
<div>
<div>
<pre><span>// Control the Sound</span></pre>
<pre><span>if</span> ( _keyboard.State[ Key.P ] )</pre>
<pre>    _mainSoundTrack.Play ( );</pre>
<pre>&nbsp;</pre>
<pre><span>if</span> ( _keyboard.State[ Key.M ] )</pre>
<pre>    _mainSoundTrack.Stop ( );</pre>
<pre>&nbsp;</pre>
<pre><span>if</span> ( _keyboard.State[ Key.N ] )</pre>
<pre>    _mainSoundTrack.NextSong ( );</pre>
<pre>&nbsp;</pre>
<pre><span>if</span> ( _keyboard.State[ Key.UpArrow ] )</pre>
<pre>    _mainSoundTrack.Volume &#43;= 10;</pre>
<pre>&nbsp;</pre>
<pre><span>if</span> ( _keyboard.State[ Key.DownArrow ] )</pre>
<pre>    _mainSoundTrack.Volume -= 10;</pre>
<pre>&nbsp;</pre>
<pre><span>if</span> ( _keyboard.State[ Key.RightArrow ] )</pre>
<pre>    _mainSoundTrack.Balance &#43;= 10;</pre>
<pre>&nbsp;</pre>
<pre><span>if</span> ( _keyboard.State[ Key.LeftArrow ] )</pre>
<pre>    _mainSoundTrack.Balance -= 10; </pre>
</div>
That's it. Start the game and press P to hear the first tune, you can use the cursor keys to change the volume (up/down) and the balance (left/right). To skip to the next song just press N, and to stop the soundtrack press M.</div>
<h4>Summary</h4>
<p>Now we have pretty much completed the pass through the basic functionality of the all the DirectX namespaces. There are many more advanced topics that could cover additional graphics classes such as HLSL (High Level Shader Language), but in the next articles
 we are going to focus on two non DirectX parts of game development - Artificial Intelligence (AI) and Physics.
</p>
<p>Without good AI and Physics, even the best designed games are no fun to play. Nothing shatters the illusion of reality more than predictable enemies or rocks floating in mid air.
</p>
<p>Together with game Physics, AI represents a major portion of the game that has no support in DirectX and limited support in other (free) libraries. We are not going to be able to fill that gap and write a fully featured AI engine, but we can cover most of
 the principles and techniques behind some of the more basic AI problems, such as chasing and evading and path finding.
</p>
<p>Until then: Happy coding. </p>
<p><b>Derek Pierson </b>is a software developer with 12 years experience designing and developing enterprise applications using a variety of programming languages. He is an enthusiastic teacher of the art of programming and believes that elegance and simplicity
 are defining features of good software. </p>
<p>Filed under: <a href="http://blogs.msdn.com/coding4fun/archive/tags/arcade/default.aspx">
arcade</a>, <a href="http://blogs.msdn.com/coding4fun/archive/tags/gaming/default.aspx">
gaming</a></p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:f7f90caa035a4962a64d9e7600d09250">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-X-Direct-Sound-Part-III</comments>
      <itunes:summary>



&amp;nbsp;
Welcome to the tenth article on beginning game development. In the last article we manipulated sounds by adding sound effects. Together with the use of 3D Buffers to make the sounds positionaly accurate we now have
 a fully featured sound system in the game. But, while we&#39;re are able to play and manipulate short sounds and sound effects we cannot play longer WMA or MP3 files with the DirectSound namespace. To accomplish that we need to turn to the AudioVideoPlayback namespace.




Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Studio Express 2005, Microsoft DirectX SDK
Hardware: Any PC capable of running DirectX 9.0
Download: Download

Previous Articles: 


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III



Why more sound 
You may be wondering why we even need to add longer sound files to the game. As I mentioned in article 8, most games include fully featured soundtracks in addition to the regular game sounds. These sound tracks are often produced specifically for the game
 much like a movie soundtrack is produced for a movie. A well made sound track can add additional drama to the game and provide a memorable experience. Sometimes these game tracks are also available as separate music CDs or downloads to bring more players to
 the game. There is really no way that anyone is going to be able to produce a nice sounding soundtrack as a WAV file. Most music uses the MP3 codec </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-X-Direct-Sound-Part-III</link>
      <pubDate>Mon, 07 Jan 2008 17:55:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-X-Direct-Sound-Part-III</guid>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-X-Direct-Sound-Part-III/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Beginning Game Development Part IX –Direct Sound Part II</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">Welcome to the ninth article on beginning game development. In the last article we added sounds to the game using the DirectSound namespace using devices, 3D Buffers, and 3D Listeners. Now we are going to further
 manipulate the sounds using the sound effect capabilities of the DirectSound namespace. Finally, since it has been a while since the last article, I am also going to update the basic game loop to a more efficient implementation.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href=""></a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input">Visual Studio Express 2005, Microsoft DirectX SDK</span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">Any PC capable of running DirectX 9.0</span></div>
<div class="entry_details"><b>Download: </b><a href="http://channel9.msdn.com/ShowPost.aspx?PostID=353244">Download</a>
<ul>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p>Previous Articles:</p>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
<h3>New Game Loop</h3>
<p>In a number of post it was pointed out that the game was not running as fast as some of the DirectX samples. The reason behind this is that the game used an older and less efficient version of the game loop. Let's go ahead and change the code to use the
 new game loop based on <a href="https://blogs.msdn.com/tmiller/archive/2005/05/05/415008.aspx">
this</a> blog by Tom Miller. </p>
<p>First create a new class called <b>NativeMethods</b> and paste the <b>Message</b> struct and extern method declaration into it. The finished class should look like this.
</p>
<b>C#</b>
<div>
<div>
<pre><span> 1:</span> <span>using</span> System;</pre>
<pre><span> 2:</span> <span>using</span> System.Runtime.InteropServices;</pre>
<pre><span> 3:</span>&nbsp; </pre>
<pre><span> 4:</span> <span>namespace</span> BattleTank2005</pre>
<pre><span> 5:</span> {</pre>
<pre><span> 6:</span> <span>class</span> NativeMethods</pre>
<pre><span> 7:</span> {</pre>
<pre><span> 8:</span> [StructLayout ( LayoutKind.Sequential )]</pre>
<pre><span> 9:</span> <span>public</span> <span>struct</span> Message</pre>
<pre><span> 10:</span> {</pre>
<pre><span> 11:</span> <span>public</span> IntPtr hWnd;</pre>
<pre><span> 12:</span> <span>public</span> <span>uint</span> msg;</pre>
<pre><span> 13:</span> <span>public</span> IntPtr wParam;</pre>
<pre><span> 14:</span> <span>public</span> IntPtr lParam;</pre>
<pre><span> 15:</span> <span>public</span> <span>uint</span> time;</pre>
<pre><span> 16:</span> <span>public</span> System.Drawing.Point p;</pre>
<pre><span> 17:</span> }</pre>
<pre><span> 18:</span>&nbsp; </pre>
<pre><span> 19:</span> [System.Security.SuppressUnmanagedCodeSecurity] <span>// We won't use this maliciously</span></pre>
<pre><span> 20:</span> [DllImport ( <span>&quot;User32.dll&quot;</span>, CharSet = CharSet.Auto )]</pre>
<pre><span> 21:</span> <span>public</span> <span>static</span> <span>extern</span> <span>bool</span> PeekMessage ( <span>out</span> Message msg, IntPtr hWnd, <span>uint</span> messageFilterMin, <span>uint</span> messageFilterMax, <span>uint</span> flags );</pre>
<pre><span> 22:</span> }</pre>
<pre><span> 23:</span> }</pre>
</div>
</div>
<p>Make sure to reference the <b>System.Runtime.InteropServices</b> namespace at the top of the class.</p>
<p>Next, add the <b>OnApplicationIdle</b> method into the <b>GameEngine</b> class
</p>
<b>C#</b>
<div>
<div>
<pre><span> 1:</span> <span>public</span> <span>void</span> OnApplicationIdle ( <span>object</span> sender, EventArgs e )</pre>
<pre><span> 2:</span> {</pre>
<pre><span> 3:</span> <span>while</span> ( AppStillIdle )</pre>
<pre><span> 4:</span> {</pre>
<pre><span> 5:</span> <span>// Render a frame during idle time (no messages are waiting)</span></pre>
<pre><span> 6:</span> _deltaTime = HiResTimer.GetElapsedTime ( );</pre>
<pre><span> 7:</span> </pre>
<pre><span> 8:</span> CheckForInput ( );</pre>
<pre><span> 9:</span> </pre>
<pre><span> 10:</span> Render ( );</pre>
<pre><span> 11:</span> }</pre>
<pre><span> 12:</span> }</pre>
</div>
</div>
<p>Then add the <b>AppStillIdle</b> property to the GameEngine class.</p>
<p><b></b></p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> <span>private</span> <span>bool</span> AppStillIdle</pre>
<pre><span> 2:</span> {</pre>
<pre><span> 3:</span> get</pre>
<pre><span> 4:</span> {</pre>
<pre><span> 5:</span> NativeMethods.Message msg;</pre>
<pre><span> 6:</span> <span>return</span> !NativeMethods.PeekMessage ( <span>out</span> msg, IntPtr.Zero, 0, 0, 0 );</pre>
<pre><span> 7:</span> }</pre>
<pre><span> 8:</span> }</pre>
</div>
</div>
<p>In the <b>Program</b> class change the <b>Main</b> method so it reads:</p>
<p><b></b></p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> [STAThread]</pre>
<pre><span> 2:</span> <span>static</span> <span>void</span> Main ( )</pre>
<pre><span> 3:</span> {</pre>
<pre><span> 4:</span> <span>using</span> ( GameEngine engine = <span>new</span> GameEngine ( ) )</pre>
<pre><span> 5:</span> {</pre>
<pre><span> 6:</span> engine.Initialize ( );</pre>
<pre><span> 7:</span> System.Windows.Forms.Application.Idle &#43;= <span>new</span> EventHandler ( engine.OnApplicationIdle );</pre>
<pre><span> 8:</span> Application.Run ( engine );</pre>
<pre><span> 9:</span> }</pre>
<pre><span> 10:</span> }</pre>
</div>
</div>
<p>Finally, remove the entire <b>OnPaint</b> method from the <b>GameEngine</b> class. You can also remove the following line from the constructor of the game engine class.</p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> <span>this</span>.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, <span>true</span>);</pre>
</div>
</div>
<p>You should see a pretty good improvement over the previous game loop. Just remember that there really is not big benefit it your game runs at 700 fps and is no fun to play, so don't get caught up in the speed over all other facets of the game.<b></b></p>
<h3>Sound effects in Games</h3>
<p>After adding the sound to BattleTank2005 in the last article, why would we bother with sound effects now? If we record the sounds ahead of time then they is really no reason to add effects to them - or is there. Sound effects are added to further manipulate
 sounds based on the active environment of the game. The simplest example would be to manipulate the base sound of footsteps and add an echo when the player is in a tunnel.
</p>
<p>As you will see a little later, DirectSound also adds an effect which allows for the manipulation of sounds to match specific pre-defined environments.
</p>
<h3>Effects </h3>
<p>There are nine sound effects in the DirectSound namespace which are referred to officially as Microsoft DirectX Media Objects (DMOs). Each class also has a large number of effect specific properties you can manipulate to pretty much get any sound effect
 you want. Here is the information from the SDK in a simple table format for easy reference.</p>
<p>
<table class="MsoTableMediumGrid1Accent1" cellspacing="0" cellpadding="0" border="1" class="MsoTableMediumGrid1Accent1">
<tbody>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Effect Name</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><b><span>Description</span></b></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Chorus</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>A voice-doubling effect created by echoing the original sound with a slight delay and slightly modulating the delay of the echo.</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Compressor</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>A reduction in the fluctuation of a signal above a certain amplitude.</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Distortion</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>Adding harmonics to the signal in such a way that, as the level increases, the top of the waveform becomes squared off or clipped.</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Echo</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>Causes sounds to be repeated after a fixed delay, usually at a diminished volume. As the repeated sounds are fed back into the mix, they are repeated again.</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Flanger (Flange)</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>An echo effect in which the delay between the original signal and its echo is very short and varies over time.</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Gargle</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>Modulates the amplitude of the signal.</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>Interactive3DLevel2Reverb (Reverb)</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>Environmental reverberation in accordance with the Interactive 3-D Audio, Level 2 (I3DL2) specification, published by the Interactive Audio Special Interest Group. See more on this later.</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>ParamEq</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>Amplifies or attenuates signals of a given frequency</span></p>
</td>
</tr>
<tr>
<td class="" valign="top" width="98">
<p class="MsoNormal"><b><span>WavesReverb</span></b></p>
</td>
<td class="" valign="top" width="419">
<p class="MsoNormal"><span>Intended for use with music and based on the Waves MaxxVerb
<br>
technology, which is licensed to Microsoft. <a href="http://www.waves.com/">http://www.waves.com/</a></span></p>
</td>
</tr>
</tbody>
</table>
</p>
<p>Out of these effect classes the <b>Interactive3DLevel2Reverb</b> is a special class, since it provides what amounts to a large set of pre-built settings representing various environments.
</p>
<p>The principle behind this class is based on the effects of the environment on the sounds we hear.</p>
<p>Basically sound we hear has three temporal components: </p>
<p>1. <u>Direct Path</u>: Straight from the source to the listener.</p>
<p>2. <u>Early Reflections</u>: Sounds that reach the listener after reflecting of one or two surfaces first. Surprisingly sounds that reflect of one surface are called
<i>first-order reflections</i>; sounds that reflect of two surfaces are called <i>
second-order reflections</i> and so on. Humans normally hear only first and second order reflections.</p>
<p>3. <u>Late Reverberations</u>: These are the combined of lower-order reflections.</p>
<p>In addition to the <b>AllParameters</b> property that all the other effect classes share, the
<b>Reverb</b> effect has two additional properties: <b>Quality</b> and <b>Preset</b>. The
<b>Quality</b> property is simply an integer value with larger values representing higher quality at the cost of processing time. The default value is 2 and the values are bounded by
<b>QualityMax</b> and <b>QualityMin</b>.</p>
<p>The <b>Preset</b> property is an <b>EffectsEnvironmentPreset</b> enumeration value that allows you to select pre-made environment settings without having to set the individual properties such as rolloff factors, diffusion etc. The enumeration includes 30
 settings including settings for: Mountains, UnderWater, Bathroom and PaddedCell. This means that you can easily manipulate pre-recorded sounds to fit your game world better without having to record and ship sounds for each possible environment.</p>
<p>The <b>ParamEqclass</b> also has a non standard feature not shared by any of the other sound effect classes. You can use this effect class multiple times on the same buffer to achieve similar control over the sound as you would with a hardware equalizer.</p>
<p>Update the SoundEffects class <br>
The first effect we are going to use in BattleTank2005 is the Interactive3DLevel2Reverb effect set to a preset value of Hangar (You have to play with the presets, some sounds do not come over very well. I originally wanted to use Plain as the preset, but one
 of the sounds ended up being distorted). </p>
<p>We want this effect to apply to all the sounds in the game, so we are going to add it to the constructor of the SoundEffectsClass.
</p>
<p>First we need to update the <b>SoundEffects</b> class (slightly unfortunately named) and set the
<b>ControlEffect</b> property of the buffer to true. This enables the buffer to be used with sound effects. In the constructor of the
<b>SoundEffects</b> class add the following line of code.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p>bufferDescription.ControlEffects = true;</p>
<p>Next we create the EffectDescription array, initializing it to the correct size. If you plan to add other effects make sure to change the size of the array accordingly. After the catch statement in the constructor add the following code.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p>Microsoft.DirectX.DirectSound.EffectDescription[] effects = new Microsoft.DirectX.DirectSound.EffectDescription[ 1 ];</p>
<p><b></b></p>
<p>Next we set the desired effect class using the DSoundHelper class.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p>effects[ 0 ].GuidEffectClass = DSoundHelper.StandardInteractive3DLevel2ReverbGuid;</p>
<p>Then we add the effect to the SecondaryBuffer for this sound.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p>AddEffects ( effects );</p>
<table class="MsoTableGrid" cellspacing="0" cellpadding="0" border="1" class="MsoTableGrid">
<tbody>
<tr>
<td class="" valign="top" width="638">
<h2>Sidebar: Casting </h2>
<p class="MsoNormal"><span>As you may have noticed the order of the SoundEffect classes in the SecondaryBuffer is significant. If you attempt to cast the object returned by the GetEffects method to another Effect class you will get a System.InvalidCastException
 exception. You could soround the call with a try/catch but this means that the framework still has to create and throw the exception, just for you to turn around and catch it again. Never use exception handling as a flow control, if you can find another way
 do so.</span></p>
<p class="MsoNormal"><b><span>C#</span></b></p>
<p class="MsoNormal"><span>EchoEffect echo = (EchoEffect)_myEngineNoise.GetEffect ( 0 );
</span></p>
<p class="MsoNormal"><span>When you call this method and the first postion in the array is not an EchoEffect class you get an exception. Since exceptions are expensive in terms of resources, the best way to cast in this circumstance is to cast like this:
</span></p>
<p class="MsoNormal"><b><span>C#</span></b></p>
<p class="MsoNormal"><span>EchoEffect echo = _myEngineNoise.GetEffect ( 0 ) as EchoEffect;
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( echo != null ) <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EffectsEcho echoParams = echo.AllParameters; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echoParams.LeftDelay = 0.9f; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; echo.AllParameters = echoParams; <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p class="MsoNormal"><span>If the cast fails then the assigned to object will be null. Easy and inexpensive.</span></p>
</td>
</tr>
</tbody>
</table>
<p>After setting the effect we need to get it back out to set its parameters. Use the correct casting method as explained above.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p>Interactive3DLevel2ReverbEffect enviroEffect = GetEffect ( 0 ) as Interactive3DLevel2ReverbEffect;</p>
<p>Check the effect variable for null before doing anything. If we have the right effect you have two choices.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p>if ( enviroEffect != null ){}</p>
<p>You can either get the Effects parameters from the <b>AllParameter</b> property of the class and then set each separate value to give you very fine grained control over the effect you are adding.
</p>
<p><b></b></p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> <span>if</span> ( enviroEffect != <span>null</span> )</pre>
<pre><span> 2:</span> {</pre>
<pre><span> 3:</span> <span>// Set all the various parameters</span></pre>
<pre><span> 4:</span> EffectsInteractive3DLevel2Reverb enviroEffects = enviroEffect.AllParameters;</pre>
<pre><span> 5:</span> </pre>
<pre><span> 6:</span> enviroEffects.DecayHfRatio = 2.0f;</pre>
<pre><span> 7:</span> enviroEffects.DecayTime = 2.0f;</pre>
<pre><span> 8:</span> enviroEffects.Density = 1.0f;</pre>
<pre><span> 9:</span> enviroEffects.Diffusion = 2.0f;</pre>
<pre><span> 10:</span> enviroEffects.Reflections = 1;</pre>
<pre><span> 11:</span> enviroEffects.Reverb = 2;</pre>
<pre><span> 12:</span> </pre>
<pre><span> 13:</span> <span>// Set them back on the effect class</span></pre>
<pre><span> 14:</span> enviroEffect.AllParameters = enviroEffects;</pre>
<pre><span> 15:</span> }</pre>
</div>
</div>
<p>You must remember to assign the modified Effects structure back to the AllParameter property of the class.</p>
<p>Or, for the&nbsp; Interactive3DLevel2ReverbEffect you can chose one of the preset environments and simply update the Preset property of the effect class.
</p>
<p><b></b></p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> <span>if</span> ( enviroEffect != <span>null</span> )</pre>
<pre><span> 2:</span> {</pre>
<pre><span> 3:</span> <span>// Choose a preset</span></pre>
<pre><span> 4:</span> enviroEffect.Preset = EffectsEnvironmentPreset.Hangar;</pre>
<pre><span> 5:</span> }</pre>
</div>
</div>
<p>Note that you do not have to set the effects class back to the SecondaryBuffer since you were manipulating only its value and you had to set it in the first place to get it. What's even cooler is that all effects can be changed while the buffer is playing
 but there is one caveat. </p>
<p>Changes to sounds may not be heard immediately since DirectX buffers about 100 milliseconds of sound starting at the play cursor. If you call any of these methods and then change the parameters then buffer rule is in effect and the changes are not heard
 immediately. </p>
<p>SecondaryBuffer.SetCurrentPosition <br>
SecondaryBuffer.SetEffects <br>
SecondaryBuffer.Stop <br>
SecondaryBuffer.Write </p>
<p>To overcome the buffer rule either call <b>Stop</b> or <b>SetCurrentPostion</b>. We take advantage of the built in
<b>Stop</b> method of our <b>SoundEffects</b> class which stops the sound and resets the stream position to the beginning of the stream, in effect clearing the buffered sound.
</p>
<p><b></b></p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> <span>public</span> <span>void</span> Stop()</pre>
<pre><span> 2:</span> {</pre>
<pre><span> 3:</span> _secondaryBuffer.Stop();</pre>
<pre><span> 4:</span> _secondaryBuffer.SetCurrentPosition(0);</pre>
<pre><span> 5:</span> }</pre>
</div>
</div>
<p>In the SoundEffects class add the following method. Before you can add effects to a
<b>SecondaryBuffer</b> you first need to stop the buffer. Then you can add the EffectDescription array passed into the method to the secondary buffer and restart it.
<i></i></p>
<p><b></b></p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> <span>public</span> <span>bool</span> AddEffects ( EffectDescription[] effectDescription )</pre>
<pre><span> 2:</span> {</pre>
<pre><span> 3:</span> Stop ( );</pre>
<pre><span> 4:</span> EffectsReturnValue[] effectreturn = _secondaryBuffer.SetEffects ( effectDescription );</pre>
<pre><span> 5:</span> Play ( );</pre>
<pre><span> 6:</span> </pre>
<pre><span> 7:</span> <span>return</span> <span>true</span>;</pre>
<pre><span> 8:</span> }</pre>
</div>
</div>
<p>Adding effects to a <b>SecondaryBuffer</b> simply requires you to pass an array of
<b>EffectDescription</b> structs to the <b>SetEffects</b> method of the secondary buffer. This method returns an array of
<b>EffectsReturnValue</b> enumerations to report the result of the operation. The return value can be any combination of seven values, including failure.</p>
<p>Next we add the method to get the effect back from the buffer</p>
<p><b>C#</b></p>
<p>public object GetEffect ( int position )</p>
<p>{</p>
<p>return _secondaryBuffer.GetEffects ( position );</p>
<p>}</p>
<p>Note that the effects are returned as objects and must be cast to their correct types before use.</p>
<p>That's it for the changes required to the SoundEffect class. You have now successfully added you first effect to the game.</p>
<p><i>As a caveat, the documentation points out that effect might not work well on very small buffer of less than 150 millisecond length.
</i></p>
<h3>Update the GameEngine class </h3>
<p>The first step is to reference the <b>Microsoft.DirectX.DirectSound</b> in the
<b>GameEngine</b> class since we are going to be creating the effects classes and structures in the
<b>ConfigureSounds</b> method of this class.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p>using Microsoft.DirectX.DirectSound;</p>
<p>Since we now have two namespaces references that contain a <b>Caps</b> class we need to update the
<b>Caps</b> class in the <b>ConfigureDevice</b> method to be fully qualified to avoid namespace collisions.</p>
<p><b></b></p>
<p><b>C#</b></p>
<p><b>Microsoft.DirectX.Direct3D.Caps</b> caps = Microsoft.DirectX.Direct3D.Manager.GetDeviceCaps ( adapterOrdinal, Microsoft.DirectX.Direct3D.DeviceType.Hardware );</p>
<p>In the <b>ConfigureSounds</b> method of the <b>GameEngine</b> class add all the following code right after the creation of the engineSound1</p>
<p><b>C#</b></p>
<div>
<div>
<pre><span> 1:</span> Microsoft.DirectX.DirectSound.EffectDescription[] effects = <span>new</span> Microsoft.DirectX.DirectSound.EffectDescription[ 1 ];</pre>
<pre><span> 2:</span> effects[ 0 ].GuidEffectClass = DSoundHelper.StandardGargleGuid;</pre>
<pre><span> 3:</span> engineSound1.AddEffects ( effects );</pre>
<pre><span> 4:</span>&nbsp; </pre>
<pre><span> 5:</span> <span>// Get the effect back so we can set it to the value we want</span></pre>
<pre><span> 6:</span> GargleEffect gargle = engineSound1.GetEffect ( 0 ) <span>as</span> GargleEffect;</pre>
<pre><span> 7:</span>&nbsp; </pre>
<pre><span> 8:</span> <span>if</span> ( gargle != <span>null</span> )</pre>
<pre><span> 9:</span> {</pre>
<pre><span> 10:</span> EffectsGargle gargle_params = gargle.AllParameters;</pre>
<pre><span> 11:</span> gargle_params.WaveShape = 1;</pre>
<pre><span> 12:</span>&nbsp; </pre>
<pre><span> 13:</span> gargle.AllParameters = gargle_params;</pre>
<pre><span> 14:</span> }</pre>
</div>
</div>
<p>Next we rinse and repeat for engineSound2 using a different effect.</p>
<div>
<div>
<pre><span> 1:</span> effects = <span>new</span> Microsoft.DirectX.DirectSound.EffectDescription[ 1 ];</pre>
<pre><span> 2:</span> effects[ 0 ].GuidEffectClass = DSoundHelper.StandardGargleGuid;</pre>
<pre><span> 3:</span> engineSound2.AddEffects ( effects );</pre>
<pre><span> 4:</span>&nbsp; </pre>
<pre><span> 5:</span> <span>// Get the effect back so we can set it to the value we want</span></pre>
<pre><span> 6:</span> FlangerEffect flanger = engineSound2.GetEffect ( 0 ) <span>as</span> FlangerEffect;</pre>
<pre><span> 7:</span>&nbsp; </pre>
<pre><span> 8:</span> <span>if</span> ( flanger != <span>null</span> )</pre>
<pre><span> 9:</span> {</pre>
<pre><span> 10:</span> EffectsFlanger flanger_params = flanger.AllParameters;</pre>
<pre><span> 11:</span> flanger_params.Waveform = 1;</pre>
<pre><span> 12:</span>&nbsp; </pre>
<pre><span> 13:</span> flanger.AllParameters = flanger_params;</pre>
<pre><span> 14:</span> }</pre>
</div>
</div>
<p>All done. Combined with the 3DListener the three effects we have applied to the game should make it easier to change the few sound we have.</p>
<p>Granted, we did not make extensive use of all the available effects. But at this point you should know how to assign any effect you wish to the sounds in the game. Experiment with the various effects and their parameters and choose those that you think fit
 your game the best.</p>
<h3>Summary </h3>
<p>Now we have pretty much completed the pass through the basic functionality of the DirectSound namespace. There are a lot of different effects you can implement using the effects provided with DirectSound. As always, the best way to learn and understand all
 of them is to experiment. In the next article we are going to use the <b>DirectXAudioVideoPlayback</b> namespace to play MP3 files to provide a soundtrack for the game. Then we are going to focus on some non DirectX parts of game development - Artificial Intelligence
 (AI). Until then: Happy coding. </p>
<p><b>Derek Pierson</b> is a software developer with 12 years experience designing and developing enterprise applications using a variety of programming languages. He is an enthusiastic teacher of the art of programming and believes that elegance and simplicity
 are defining features of good software. </p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:aad76a64dd1c4c28a6ea9e7600d1707a">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IX-Direct-Sound-Part-II</comments>
      <itunes:summary>



&amp;nbsp;
Welcome to the ninth article on beginning game development. In the last article we added sounds to the game using the DirectSound namespace using devices, 3D Buffers, and 3D Listeners. Now we are going to further
 manipulate the sounds using the sound effect capabilities of the DirectSound namespace. Finally, since it has been a while since the last article, I am also going to update the basic game loop to a more efficient implementation.



Derek Pierson


Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Studio Express 2005, Microsoft DirectX SDK
Hardware: Any PC capable of running DirectX 9.0
Download: Download








Previous Articles: 


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III



New Game Loop
In a number of post it was pointed out that the game was not running as fast as some of the DirectX samples. The reason behind this is that the game used an older and less efficient version of the game loop. Let&#39;s go ahead and change the code to use the
 new game loop based on 
this blog by Tom Miller.  
First create a new class called NativeMethods and paste the Message struct and extern method declaration into it. The finished class should look like this.
 
C#


 1: using System;
 2: using System.Runtime.InteropServices;
 3:&amp;nbsp; 
 4: namespace BattleTank2005
 5: {
 6: class NativeMethods
 7: {
 8: [StructLayout ( LayoutKind.Sequential )]
 9: public struct Message
 10: {
 11: public IntPtr hWnd;
 12: pub</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IX-Direct-Sound-Part-II</link>
      <pubDate>Fri, 02 Nov 2007 23:40:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IX-Direct-Sound-Part-II</guid>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IX-Direct-Sound-Part-II/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Beginning Game Development: Part VII –Terrain and Collision Detection</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">Welcome to the seventh article on beginning game development. In this article, we are going to refine the way the terrain looks and start incorporating it into our game.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b></div>
<div class="entry_details">
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044454/BattleTank_Part7_CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044454/BattleTank_Part7_VB.msi">VB Download</a></li></ul>
</div>
<p>&nbsp;</p>
<div class="entry_details"><b>Beginning Game Development Series</b></div>
<ol>
<li><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
</td>
</tr>
</tbody>
</table>
</span>
<h1>Introduction</h1>
<p>Welcome to the seventh article on beginning game development. In the last article, we covered how lights and materials can add realism to a scene. We also discussed how to create a terrain from a heightmap, and finally added fonts to the application. In
 this article, we are going to refine the way the terrain looks and start incorporating it into our game.</p>
<p>Before we start, let's do the obligatory code cleanup, incorporating all the feedback I received.</p>
<h1>Code cleanup</h1>
<p>The cleanup for this article consists of some minor refactoring to keep the code clean and some changes to the lights and normals for the lighting.
</p>
<ul>
<li>Handle <b>DeviceResizing</b> event. </li><li>Manage <b>Device</b> events (see next section). </li><li>Changed the ambient and diffuse light to be darker. If you use <code>Color.White</code> for the ambient light, there is already 100% so any other light is not visible. Instead, I am now using
<code>Color.FromArgb ( 64, 64, 64 )</code> for the ambient and <code>Color.FromArgb ( 128, 128, 128 )</code> for the diffuse light.
</li><li>Added _<code>device.RenderState.NormalizeNormals = true;</code> so that the normals are recalculated when scaling the terrain. You can remove this call if you are not scaling the terrain since it has some performance cost.
</li><li>In the last article, I incorrectly stated that <code>presentParams.AutoDepthStencilFormat = DepthFormat.D16;</code> was setting up a
<b>DepthStencil</b>, this code is actually settings up a <b>DepthBuffer</b>. For a clarification check out these links:
<ul>
<li><a href="http://en.wikipedia.org/wiki/Depth_buffer">http://en.wikipedia.org/wiki/Depth_buffer</a>
</li><li><a href="http://en.wikipedia.org/wiki/Stencil_buffer">http://en.wikipedia.org/wiki/Stencil_buffer</a>
</li></ul>
</li></ul>
<h1>Device Handling</h1>
<p>Up to this point we have pretended that once we have initialized the graphics device nothing can go wrong until we are done using it. In the real world things do go wrong, and in the DirectX world losing the device can happen in response to a number of user
 actions, such as Alt-tabbing from application to application, minimizing a window, or certain power management functions.</p>
<p>Once the device has been lost, all render functions will silently fail and the render operations will not return an error code even though they are really failing. Any calls to render functions, such as
<code>DrawIndexedPrimitives</code> are discarded until the device is reset. Any call to
<code>Device.Present</code> however will cause an exception.</p>
<p>There are two exceptions that are associated with lost devices:</p>
<p><b>DeviceLostException:</b> The device is lost and can<i>not</i> be reset.</p>
<p><b>DeviceNotResetException:</b> The device is lost and can be reset.</p>
<p>To detect the device lost state, DirectX provides the <b>DeviceLost</b> event for the
<b>Device</b> object. Once the Device has been lost, it must be reset to function properly. You can also check if a device is in the lost state using the
<b>CheckCopperativeLevel</b> property of the device.</p>
<p>Once the Device is lost the application will query the Device and determine if it can be restored to the operational state. If it can be restored, then all video memory resources placed in
<b>Pool.Default</b> and swap chains are destroyed and the Reset method is called. Resources created in
<b>Pool.Managed</b> are backed by system memory and do not have to be destroyed and recreated. If the device cannot be reset then the application waits until it can be restored.</p>
<p>The Reset method is the only method that has any effect on the application once a device has been lost and is the only way to change a device from the lost state to the operational state. The Reset method will fail unless the application has released all
 resources allocated, so resources created in the <b>DeviceReset</b> event should be destroyed in the
<b>DeviceLost</b> event.</p>
<p>Enough theory. We need to update BattleTank2005 to detect the device reset and lost events and react to them.</p>
<p>At the bottom of the <b>ConfigureDevice</b> method of the <b>GameEngine</b> class add the following code:</p>
<p><b>Visual C#</b></p>
<pre><code>_device.DeviceReset&#43;=new EventHandler(OnDeviceReset);<br>_device.DeviceLost&#43;=new EventHandler(OnDeviceLost);<br>_device.Disposing&#43;=new EventHandler(OnDeviceDisposing);<br>OnDeviceReset ( this, null );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>AddHandler m_device.DeviceLost, AddressOf OnDeviceLost<br>AddHandler m_device.DeviceReset, AddressOf OnDeviceReset<br>AddHandler m_device.Disposing, AddressOf OnDeviceDisposing<br>OnDeviceReset(Me, Nothing)</code></pre>
<p>Now add the following three methods to the GameEngine class:</p>
<p><b>Visual C#</b></p>
<pre><code>private void OnDeviceReset(object sender, EventArgs e)<br>{<br>    if ( _font != null )<br>        _font.OnResetDevice ( );<br>    // Turn on some low level ambient light<br>    _device.RenderState.Ambient = Color.LightGray;<br>}<br>private void OnDeviceLost(object sender, EventArgs e)<br>{<br>    if ( _font != null &amp;&amp; _font.Disposed == false )<br>        _font.OnLostDevice ( );<br>}<br>private void OnDeviceDisposing(object sender, EventArgs e)<br>{<br>    if ( _mouse != null )<br>        _mouse.Dispose ( );<br>    if ( _keyboard !=null )<br>        _keyboard.Dispose ( );<br>    if ( _terrain != null )<br>        terrain.Dispose ( );<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private Sub OnDeviceReset(ByVal sender As Object, ByVal e As EventArgs)<br>    If (Not (m_font) Is Nothing) Then<br>        m_font.OnResetDevice()<br>    End If<br>    m_device.Transform.Projection = m_camera.Projection<br>    ' Turn on some low level ambient light<br>    m_device.RenderState.Ambient = Color.FromArgb(64, 64, 64)<br>    m_device.RenderState.NormalizeNormals = True<br>End Sub<br>Private Sub OnDeviceLost(ByVal sender As Object, ByVal e As EventArgs)<br>    If Not (m_font Is Nothing) AndAlso m_font.Disposed = False Then<br>        m_font.OnLostDevice()<br>    End If<br>End Sub<br>Private Sub OnDeviceDisposing(ByVal sender As Object,<br>  ByVal e As EventArgs)<br>    If (Not (m_mouse) Is Nothing) Then<br>        m_mouse.Dispose()<br>    End If<br>    If (Not (m_keyboard) Is Nothing) Then<br>        m_keyboard.Dispose()<br>    End If<br>    If (Not (m_terrain) Is Nothing) Then<br>        m_terrain.Dispose()<br>    End If<br>End Sub</code></pre>
<p>Check out the comments in the code for a more detailed explanation.</p>
<h1>Textures</h1>
<p>In the last article we used a single texture file and stretched it across the terrain to make the terrain more realistic. Textures provide us with the ability to map images onto the surfaces of our shapes
</p>
<p>When you apply a 2D texture to a 3D shape you need to somehow match the texture coordinates to the coordinates of the shape. You accomplish this by mapping the coordinates of the texture to the coordinates of the shape. The Tu and Tv values are nothing other
 than the X/Y coordinates of the texture (a single u,v pair is also called a &quot;texel&quot;). The main difference is that texture coordinates are two dimensional and fall into the range of 0.0f – 1.0f.</p>
<p><img height="227" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044454/beginning7_1.gif" width="250"></p>
<p>In the code we simply assign each texture coordinate to the matching mesh coordinate by dividing it by the number of quads. Doing this results in a single texel spanning a single quad of the terrain.</p>
<p><b>Visual C#</b></p>
<pre><code>vertex.Tu = (float)x / _numberOfQuadsX;<br>vertex.Tv = (float)z / _numberOfQuadsZ</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>vertex.Tu = CType(x, Single) / _numberOfQuadsX<br>vertex.Tv = CType(z, Single) / _numberOfQuadsZ</code></pre>
<p>In addition to this simple approach you could also use multiple textures at a time. This is called
<i>multitexturing</i> and is a topic well worth exploring for any developer trying to create the most realistic terrain. We are only using single texture right now, but multitexturing explains why we passed a zero to the
<b>SetTexture</b> call in the <i>Render</i> method of the <b>Terrain</b> class. The zero, as you may have guessed identified the texture as the first texture to be used.</p>
<p><b>Visual C#</b></p>
<pre><code>_device.SetTexture ( 0, _terrainTexture );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>_device.SetTexture(0, _terrainTexture)</code></pre>
<p>There are a number of other tweaks you can do to the way the texture is displayed but none really changes the way we are using the terrain texture in code.</p>
<p>DirectX uses a technique called &quot;Filtering&quot; to smooth out any distortions caused when a texture triangle is magnified or minified to fit the screen triangle. You should experiment with changing the
<b>SamplerStageStates</b> value passed to the <b>Device.SetSamplerState</b> method. As always you are making a tradeoff between speed and detail.</p>
<p>Another solution to the distortion problem is to use <b>mipmaps</b>. This approach uses a series of smaller lower resolution textures chained together. If you use the
<b>FromFile</b> method of the <b>TextureLoader</b>, DirectX automatically generates a mipmap chain. If you are graphically inclined or want to squeeze the best possible result from the texture you can also use the texture editor included with the DirectX SDK
 (DxTex.exe) to generate a mipmap chain. (This editor is also useful in a number of other texture manipulation functions.)</p>
<p>The result we achieved using the Down.jpg file in BattleTank2005 was passable but it was pretty boring. If you use a third party tool you can create a terrain texture customized for your heightmap with much better results than we achieved, but what if you
 want to generate random terrain for each level? The answer is procedural terrain generation.</p>
<h2>Procedural Terrain Generation</h2>
<p>The texture we used was the bottom of the skybox, and the coloration and highlights in the texture had no relationship to the landscape created by the heightmap. Another option is to use this same technique, but use a texture file specifically created for
 the heightmap (or more accurately the heightmap and texture are created at the same time) using a program such as Terragen. This approach lets you fiddle with the texture file until it is exactly the way you want it, but it is fairly labor intensive, especially
 if you want to offer the player a large number of maps to play on.</p>
<p>Yet another approach is to generate the texture file with a heightmap and a couple of texture files using a process called &quot;Procedural Texture Generation.&quot; With this approach you can use texture files to represent the terrain at various heights. For example,
 you could specify a sand texture for low elevations, grass texture for the next elevation levels, rock texture for the next and finally a snow texture for the highest elevations.
</p>
<p>The first step is to separate the terrain into regions by elevations. Remember for the last article that we can represent 256 distinct elevations using a grayscale heightmap. If you divide that value by four then each region covers 64 elevation units.</p>
<table class="" cols="2" rules="all" width="260" border="1" frame="box">
<tbody>
<tr valign="top">
<td class="" width="35%">Texture</td>
<td class="" width="65%">Elevation Range</td>
</tr>
<tr valign="top">
<td class="" width="35%">Sand</td>
<td class="" width="65%">0-64</td>
</tr>
<tr valign="top">
<td class="" width="35%">Grass</td>
<td class="" width="65%">64-128</td>
</tr>
<tr valign="top">
<td class="" width="35%">Rock</td>
<td class="" width="65%">128-192</td>
</tr>
<tr valign="top">
<td class="" width="35%">Snow</td>
<td class="" width="65%">192-256</td>
</tr>
</tbody>
</table>
<br>
<p>Each of these regions is associated with a texture file which means that the resulting terrain texture will use the color of the texture at that location.</p>
<p>There is one more refinement we need to add, however. Rather than simply using the same color for all elevations within a range we want to blend the textures so that there is a more gradual change of textures from region to region. We accomplish this by
 calculating the percentage of each texture at each elevation and then blending the colors.</p>
<p>To create the texture map I added another Solution to the source code called <b>
TerrainGenerator</b>. This console application takes four texture files and one heightmap in RAW format and creates the terrain texture. If you were using some of the methods I mentioned in my previous article to automatically generate the heightmap, you could
 combine these two features and auto-generate the terrain for each level on the fly. I will leave that implementation up to you.</p>
<p>All of the code in the main method simply manages the input parameters and does some validation so I will not cover it in detail. The real meat of the application is the
<b>CreateTerrainTexture</b> method. After setting up some arrays and variables to hold the various pieces of data we enter a double loop which performs the actual work.</p>
<p><b>Visual C#</b></p>
<pre><code>for ( int z = 0; z &lt; _numberOfVerticesZ; z&#43;&#43; )<br>{<br>    for ( int x = 0; x &lt; _numberOfVerticesX; x&#43;&#43; )<br>    {<br>        // Implementation code below<br>    }<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Dim z As Integer = 0<br>While z &lt; _numberOfVerticesZ<br>    Dim x As Integer = 0<br>    While x &lt; _numberOfVerticesX<br>        'Implementation code below<br>        x = x &#43; 1<br>    End While<br>    z = z &#43; 1<br>End While</code></pre>
<p>The first step is to get the elevation value at the coordinates in question. </p>
<p><b>Visual C#</b></p>
<pre><code>elevation =(float) heightmap[ ( z * _numberOfVerticesZ ) &#43; x ];</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>elevation = CType(heightmap(((z * _numberOfVerticesZ) &#43; x)), Single)</code></pre>
<p>Using this value we then compute the texture percent (for example, how much of each texture is visible at that elevation). Since we have four textures in this sample we do this four times.</p>
<p><b>Visual C#</b></p>
<pre><code>textureFactor[0] = ComputeTexturePercent ( 256, elevation );<br>textureFactor[1] = ComputeTexturePercent ( 192, elevation );<br>textureFactor[2] = ComputeTexturePercent ( 128, elevation );<br>textureFactor[3] = ComputeTexturePercent ( 64, elevation );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>textureFactor(0) = ComputeTexturePercent(256, elevation)<br>textureFactor(1) = ComputeTexturePercent(192, elevation)<br>textureFactor(2) = ComputeTexturePercent(128, elevation)<br>textureFactor(3) = ComputeTexturePercent(64, elevation)</code></pre>
<p>The actual <b>ComputeTexturePercent</b> method returns a value between 0.0 and 1.0 representing the percent of the texture visible at a given height.</p>
<p><b>Visual C#</b></p>
<pre><code>private static float ComputeTexturePercent ( float h1, <br>    float elevation)<br>{<br>    float regionSize = 256/4;<br>    float texturePercent = ( regionSize - Math.Abs ( elevation-h1 ) )<br>     / regionSize;<br>    if ( texturePercent &lt; 0.0f )<br>        texturePercent = 0.0f;<br>    else if ( texturePercent &gt; 1.0f )<br>        texturePercent = 1.0f;<br>    return texturePercent;<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private Function ComputeTexturePercent(ByVal h1 As Single,<br>  ByVal elevation As Single) As Single<br>    Dim regionSize As Single = (256 / 4)<br>    Dim texturePercent As Single = ((regionSize - Math.Abs((<br>        elevation - h1))) / regionSize)<br>    If (texturePercent &lt; 0.0!) Then<br>        texturePercent = 0.0!<br>    ElseIf (texturePercent &gt; 1.0!) Then<br>        texturePercent = 1.0!<br>    End If<br>    Return texturePercent<br>End Function</code></pre>
<p>The next step is to get the RGB values for the coordinate from each of the textures.
</p>
<p><b>Visual C#</b></p>
<pre><code>for ( int i = 0; i &lt; 4; i&#43;&#43; )<br>{<br>    Color color = textures[i].GetPixel ( x, z );<br>    oldR[i] = color.R;<br>    oldG[i] = color.G;<br>    oldB[i] = color.B;<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Dim i As Integer = 0<br>Do While (i &lt; 4)<br>    Dim color As Color = textures(i).GetPixel(x, z)<br>    oldR(i) = color.R<br>    oldG(i) = color.G<br>    oldB(i) = color.B<br>    i = (i &#43; 1)<br>Loop</code></pre>
<p>This &quot;old&quot; value is then used together with the texture factor to compute the new RGB value.
</p>
<p><b>Visual C#</b></p>
<pre><code>Dim i As Integer = 0<br>Do While (i &lt; 4)<br>    Dim color As Color = textures(i).GetPixel(x, z)<br>    oldR(i) = color.R<br>    oldG(i) = color.G<br>    oldB(i) = color.B<br>    i = (i &#43; 1)<br>Loop</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>newR = ((textureFactor(0) * oldR(0)) &#43; <br>       ((textureFactor(1) * oldR(1)) &#43; <br>       ((textureFactor(2) * oldR(2)) &#43; <br>       (textureFactor(3) * oldR(3)))))<br>newG = ((textureFactor(0) * oldG(0)) &#43; <br>       ((textureFactor(1) * oldG(1)) &#43; <br>       ((textureFactor(2) * oldG(2)) &#43; <br>       (textureFactor(3) * oldG(3)))))<br>newB = ((textureFactor(0) * oldB(0)) &#43; <br>       ((textureFactor(1) * oldB(1)) &#43; <br>       ((textureFactor(2) * oldB(2)) &#43; <br>       (textureFactor(3) * oldB(3)))))</code></pre>
<p>The final step is to create the new color and set the pixel in the terrain texture to that color.</p>
<p><b>Visual C#</b></p>
<pre><code>Color newColor = Color.FromArgb ( (int)newR, (int)newG, (int)newB );<br>finalTexture.SetPixel ( x, z, newColor );</code></pre>
<p><b>Visual Basic</b></p>
<pre>Dim newColor As Color = Color.FromArgb(CType(newR, Integer), <br>    CType(newG, Integer), CType(newB, Integer))<br>finalTexture.SetPixel(x, z, newColor)</pre>
<p>When all is said and done, this is the result.</p>
<p><img height="250" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044454/beginning7_2.gif" width="500"></p>
<p>The approach we took to create the terrain texture is the simplest approach possible. As I stated in the last article there are people that do nothing else but work on better ways to create realistic-looking terrain. Some enhancements that could be made
 to our approach are: </p>
<ul>
<li>Take into account slope. For example: Snow would not stick to an almost vertical surface, instead the underlying terrain would show. You could represent this as showing the snow texture when the slope is between 0% and 80% but show rock when the slope is
 greater then 80%. </li><li>Angle of the sun and the shade areas resulting from this. Snow might exist at lower elevations that are in the shade, but not at higher elevations not in the shade.
</li><li>Climate. Different vegetation will grow in wetter climates and the terrain will drain differently depending on slope and ability of the water to run off.
</li><li>Using a number of different textures for the same elevation range (i.e. different grass textures) increases the realism.
</li></ul>
<p>Regardless of how precise you are when creating the terrain, the resolution of the terrain texture has the single biggest impact on how realistic the scene looks. As usual you must learn how to balance the cost of loading a large texture file that provides
 a high level of detail with the performance cost.</p>
<p>Before we integrate the terrain generated we need to (or I want to) update the way we move the camera around.</p>
<h2>New Camera</h2>
<p>The camera class we have used so far does its job, but I want to replace it with a more traditional implementation of a First Person Shooter camera.
</p>
<p>Check out this article to see the theory behind the changes: <a href="http://www.toymaker.info/Games/html/camera.html">
http://www.toymaker.info/Games/html/camera.html</a>.</p>
<p>As we are moving around on the terrain we maintain the pitch values provided by the mouse. To make the camera a more realistic first person camera we need to take control the Yaw, Roll and Pitch of the camera. This way we can adjust the camera to the underlying
 terrain. For example: if we are driving up the side of a steep hill, the pitch and roll of the camera should be equal to the slope we are on. The Yaw of the camera is the same as the heading and changes only based on user input, not on any terrain features.</p>
<p>Yaw, Pitch and Roll combine to describe the attitude of an object. Yaw expresses the rotation around the Y axis, Pitch the X axis and Roll the Z axis.</p>
<p><img height="203" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044454/beginning7_3.gif" width="494"></p>
<p>To implement this change we are going to add a couple of methods to the camera class and make some other minor modifications.</p>
<p>First we add a method each to control the Yaw, Pitch and Roll.</p>
<p><b>Visual C#</b></p>
<pre><code>public void AdjustYaw ( float radians )<br>{<br>    Matrix rotation = Matrix.RotationAxis (_up, radians );<br>    _right = Vector3.TransformNormal ( _right, rotation );<br>    _look = Vector3.TransformNormal ( _look, rotation );<br>}<br>public void AdjustPitch ( float radians )<br>{<br>    _pitch -= radians;<br>    if ( _pitch &gt; _maxPitch )<br>    {<br>        radians &#43;= _pitch - _maxPitch;<br>    }<br>    else if ( _pitch &lt; -_maxPitch )<br>    {<br>        radians &#43;= _pitch &#43; _maxPitch;<br>    }<br>    Matrix rotation = Matrix.RotationAxis ( _right, radians );<br>    _up = Vector3.TransformNormal ( _up, rotation );<br>    _look = Vector3.TransformNormal ( _look, rotation );<br>}<br>public void AdjustRoll ( float radians )<br>{<br>    Matrix rotation = Matrix.RotationAxis( _look, radians );<br>    _right = Vector3.TransformNormal( _right, rotation );<br>    _up = Vector3.TransformNormal( _up, rotation );<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Public Sub AdjustYaw(ByVal radians As Single)<br>    If (radians = 0.0!) Then<br>        Return<br>    End If<br>    Dim rotation As Matrix = Matrix.RotationAxis(_up, radians)<br>    _right = Vector3.TransformNormal(_right, rotation)<br>    _look = Vector3.TransformNormal(_look, rotation)<br>End Sub<br>Public Sub AdjustPitch(ByVal radians As Single)<br>    If (radians = 0.0!) Then<br>        Return<br>    End If<br>    _pitch = (_pitch - radians)<br>    If (_pitch &gt; _maxPitch) Then<br>        radians = (radians _<br>                &#43; (_pitch - _maxPitch))<br>    ElseIf (_pitch _<br>                &lt; (_maxPitch * -1)) Then<br>        radians = (radians _<br>                    &#43; (_pitch &#43; _maxPitch))<br>    End If<br>    Dim rotation As Matrix = Matrix.RotationAxis(_right, radians)<br>    _up = Vector3.TransformNormal(_up, rotation)<br>    _look = Vector3.TransformNormal(_look, rotation)<br>End Sub<br>Public Sub AdjustRoll(ByVal radians As Single)<br>    If (radians = 0.0!) Then<br>        Return<br>    End If<br>    Dim rotation As Matrix = Matrix.RotationAxis(_look, radians)<br>    _right = Vector3.TransformNormal(_right, rotation)<br>    _up = Vector3.TransformNormal(_up, rotation)<br>End Sub</code></pre>
<p>Then we change the Update method to compute the View matrix. </p>
<p><b>Visual C#</b></p>
<pre><code>public void Update (  )<br>{<br>    if ( Vector3.Length ( _velocity ) &gt; _maxVelocity )<br>    _velocity = Vector3.Normalize ( _velocity ) * _maxVelocity;<br>    // Update <br>    _postion &#43;= _velocity;<br>    // Stop<br>    _velocity = new Vector3 ( );<br>    _lookAt = _postion &#43; _look;<br>    <br>    Vector3 up = new Vector3 ( 0.0f, 1.0f, 0.0f );<br>    _viewMatrix = Matrix.LookAtLH ( _postion, _lookAt, up );<br>    _right.X = _viewMatrix.M11;<br>    _right.Y = _viewMatrix.M21;<br>    _right.Z = _viewMatrix.M31;<br>    _up.X = _viewMatrix.M12;<br>    _up.Y = _viewMatrix.M22;<br>    _up.Z = _viewMatrix.M32;<br>    _look.X = _viewMatrix.M13;<br>    _look.Y = _viewMatrix.M23;<br>    _look.Z = _viewMatrix.M33;<br> <br>    float lookLengthOnXZ = (float)Math.Sqrt ( _look.Z * _look.Z &#43;<br>    _look.X * _look.X );<br>    _pitch = (float)Math.Atan2 ( _look.Y, lookLengthOnXZ );<br>    _yaw = (float)Math.Atan2 ( _look.X, _look.Z );<br> <br>    ComputeViewFrustum ( );<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Public Sub Update()<br>    If (Vector3.Length(_velocity) &gt; _maxVelocity) Then<br>        _velocity = (Vector3.Normalize(_velocity) * _maxVelocity)<br>    End If<br>    ' Update <br>    _postion = (_postion &#43; _velocity)<br>    ' Stop<br>    _velocity = New Vector3<br>    _lookAt = (_postion &#43; _look)<br>    Dim up As Vector3 = New Vector3(0.0!, 1.0!, 0.0!)<br>    _viewMatrix = Matrix.LookAtLH(_postion, _lookAt, up)<br>    _right.X = _viewMatrix.M11<br>    _right.Y = _viewMatrix.M21<br>    _right.Z = _viewMatrix.M31<br>    _up.X = _viewMatrix.M12<br>    _up.Y = _viewMatrix.M22<br>    _up.Z = _viewMatrix.M32<br>    _look.X = _viewMatrix.M13<br>    _look.Y = _viewMatrix.M23<br>    _look.Z = _viewMatrix.M33<br>    Dim lookLengthOnXZ As Single = CType(Math.Sqrt(((_look.Z * _look.Z) _<br>                    &#43; (_look.X * _look.X))), Single)<br>    _pitch = CType(Math.Atan2(_look.Y, lookLengthOnXZ), Single)<br>    _yaw = CType(Math.Atan2(_look.X, _look.Z), Single)<br>    ComputeViewFrustum()<br>End Sub</code></pre>
<p>We also added a max pitch value and a control value for the camera speed. The camera speed is adjusted using the
<b>deltaTime</b> variable to yield a smoother motion. </p>
<p><b>Visual C#</b></p>
<pre><code>m_maxPitch = Geometry.DegreeToRadian( 89.0f )<br>m_maxVelocity = 1.0f;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Dim _maxPitch As Single = Geometry.DegreeToRadian(89.0F)<br>Dim _maxVelocity As Single = 1.0F</code></pre>
<p>Next we need to instantiate the camera a little differently. In the Initialize method of the GameEngine class add the following code.</p>
<p><b>Visual C#</b></p>
<pre><code>_camera = new Camera ( );<br>_camera.MaxVelocity = 100.0f;<br>_camera.Position = new Vector3 ( 0.0f, 0.0f, 0.0f );<br>_camera.LookAt = new Vector3 ( 0.0f, 0.0f, 0.0f );<br>_camera.Update ( );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_camera = New Camera<br>m_camera.MaxVelocity = 100.0F<br>m_camera.Position = New Vector3(0.0F, 0.0F, 0.0F)<br>m_camera.LookAt = New Vector3(0.0F, 0.0F, 0.0F)<br>m_camera.Update()</code></pre>
<p>With these changes to the camera class, integrating the terrain into the game will be a lot easier. It also shows you that there are many ways of accomplishing the same task. You should experiment with the various versions and choose the one you like best.</p>
<h2>Terrain Elevation</h2>
<p>In the last article you may have noticed that we used the Scaling matrix to change the size of the terrain mesh before rendering. These scale variables must be applied to any coordinate resolutions, so I moved them into separate variables. Remember to set
 add <code>_device.RenderState.NormalizeNormals = true</code> to recompute the normals.</p>
<p>At the bottom of the Terrain class add the following code.</p>
<p><b>Visual C#</b></p>
<pre><code>private float _scaleX = 1.0f;<br>private float _scaleZ = 1.0f;<br>private float _scaleY = 0.3f;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Dim _scaleX As Single = 4.0!<br>Dim _scaleZ As Single = 4.0!<br>Dim _scaleY As Single = 0.5!</code></pre>
<p>In the Render method of the Terrain class change the line of code that computes up the scaling matrix to:</p>
<p><b>Visual C#</b></p>
<pre><code>_device.Transform.World = Matrix.Scaling ( _scaleX, _scaleY, _scaleZ );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>_device.Transform.World = Matrix.Scaling(_scaleX, _scaleY, _scaleZ)</code></pre>
<p>Now we can determine the height (Y) of the terrain at any given coordinate set, taking into account the scale applied. Add the following method to the Terrain class.</p>
<p><b>Visual C#</b></p>
<pre><code>public float TerrainHeight ( int x, int z )<br>{<br>    x = x / (int)_scaleX;<br>    z = z / (int)_scaleZ;<br>    if ( _isHeightMapRAW )<br>    return (float)( _elevationsRAW[ ( z * _numberOfVerticesZ )<br>        &#43; x] ) * _scaleY;<br>    else<br>    return (float)( _elevations[(int)x,(int)z] ) / _scaleY;<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Public Function TerrainHeight(ByVal x As Integer, ByVal z As Integer) As Single<br>    x = (x / CType(_scaleX, Integer))<br>    z = (z / CType(_scaleZ, Integer))<br>    If m_isHeightMapRAW Then<br>        Return (CType(_elevationsRAW(((z * _numberOfVerticesZ) &#43; x)),<br>            Single) * _scaleY)<br>    Else<br>        Return (CType(_elevations(CType(x, Integer), CType(z, Integer)), <br>           Single) / _scaleY)<br>    End If<br>End Function<br></code></pre>
<p>All we are doing is retrieving the Y value from the elevation array based on the X and Z coordinates passed in. Make sure to change the scaling values from multiplication to division when the scaling value is greater then 1.</p>
<p>Now we need to adjust the Y coordinate of the camera to the appropriate Y value of the terrain. In the
<b>Render</b> method of the <b>GameEngine</b> class add the following line of code immediately after the call to the Update method of the camera.</p>
<p><b>Visual C#</b></p>
<pre><code>camera.SetHeight ( _terrain.TerrainHeight ( (int)_camera.Position.X, (int)_camera.Position.Z ) );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_camera.SetHeight(m_terrain.TerrainHeight(m_camera.Position.X, <br>    m_camera.Position.Z))</code></pre>
<p>At this point you would probably want to disable the Q and Z keys so the players cannot change the Y values on their own. The last step is to add a new method to the camera class that allows us to directly set the height of the camera. The
<b>heightOfTurret</b> variable ensures that we are slightly above the terrain to avoid clipping as we drive around. Go ahead and change the value to 0 to see what I mean.</p>
<p><b>Visual C#</b></p>
<pre><code>public void SetHeight ( float y )<br>{<br>    float heightOfTurret = 1.5f;<br>    _postion.Y = y &#43; heightOfTurret;<br>}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Public Sub SetHeight(ByVal y As Single)<br>    Dim heightOfTurret As Single = 1.5!<br>    _postion.Y = (y &#43; heightOfTurret)<br>End Sub</code></pre>
<p>The net effect of these changes is that we can now &quot;drive&quot; across the terrain. You need to make sure to disable the input for moving along the Y axis (Q and Z) when you are doing this. There are a number of other changes that need to be made to make the
 camera and the terrain work together for a smooth game experience. I am out of space but you can see how you would constrain the movement of the player/camera to the extents of the terrain (to make sure we don't fall of the terrain mesh). You could also adjust
 the pitch and roll of the camera based on the slope of the terrain. Hint: the heading is important in both instances.</p>
<h2>Summary</h2>
<p>There are a number of more advanced terrain concepts which I purposely skipped for right now but will return to later on. If you search for &quot;Terrain DirectX&quot; you will get more information then you can possibly digest, but then remember that some developers
 specialize in nothing else.</p>
<p>Until then: Happy coding.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:93765707ca9d430aab989e7600d8b897">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VII-Terrain-and-Collision-Detection</comments>
      <itunes:summary>



&amp;nbsp;
Welcome to the seventh article on beginning game development. In this article, we are going to refine the way the terrain looks and start incorporating it into our game.



Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware: 
Download: 


C# Download
VB Download

&amp;nbsp; 
Beginning Game Development Series

Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III








Introduction
Welcome to the seventh article on beginning game development. In the last article, we covered how lights and materials can add realism to a scene. We also discussed how to create a terrain from a heightmap, and finally added fonts to the application. In
 this article, we are going to refine the way the terrain looks and start incorporating it into our game. 
Before we start, let&#39;s do the obligatory code cleanup, incorporating all the feedback I received. 
Code cleanup
The cleanup for this article consists of some minor refactoring to keep the code clean and some changes to the lights and normals for the lighting.
 

Handle DeviceResizing event. Manage Device events (see next section). Changed the ambient and diffuse light to be darker. If you use Color.White for the ambient light, there is already 100% so any other light is not visible. Instead, I am now using
Color.FromArgb ( 64, 64, 64 ) for the ambient and Color.FromArgb ( 128, 128, 128 ) for the diffuse light.
A</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VII-Terrain-and-Collision-Detection</link>
      <pubDate>Thu, 09 Nov 2006 13:56:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VII-Terrain-and-Collision-Detection</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1044454_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1044454_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>12</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VII-Terrain-and-Collision-Detection/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Beginning Game Development: Part VI - Lights, Materials and Terrain</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This is Part 6 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers Lights and Materials and gives a very basic introduction to terrain.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/windows/directx/default.mspx">DirectX SDK</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b></div>
<div class="entry_details">
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/BattleTank2005Part6-CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/BattleTank2005Part6-VB.msi">VB Download</a></li></ul>
</div>
<div class="entry_details"><strong>Beginning Game Development Series</strong></div>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
<a class="" href="http://msdn.microsoft.com/coding4fun/gaming/arcade/article.aspx?articleid=999786&amp;title=Beginning&#43;Game&#43;Development%3a&#43;Part&#43;VIII&#43;-&#43;DirectSound"></a></td>
</tr>
</tbody>
</table>
</span>
<h2>Introduction</h2>
<p>Welcome to the sixth article on beginning game development. Last time I promised we would discuss lighting, terrain building and collision detecting in this article, but there is enough information in terrain building alone to cover multiple articles and
 the same holds true for collision detection. So instead, I am going to cover Lights and Materials and give a very basic introduction to terrain building in this article, and go into more depth about terrain building and collision detection in the next article.</p>
<p>Before we start, let's do the obligatory code cleanup, incorporating all the feedback I received.</p>
<h2>Code cleanup</h2>
<p>The cleanup for this article consists mainly of version upgrades and some minor performance improvements.
</p>
<ul>
<li>Updated to the release version of <a href="http://msdn.microsoft.com/vstudio/express/default.aspx">
Visual Studio Express</a><br>
</li><li>Updated to the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=1C8DC451-2DBE-4ECC-8C57-C52EEA50C20A">
October 2005 DirectX SDK</a>.<br>
</li><li>Added the following code to the <b>ConfigureDevice</b> method. Depth stencils enable the application to mask sections of the rendered image so they are not displayed, which increases performance. This code simply enables a 16-bit Z-Buffer depth stencil.
<br>
</li><li><code>presentParams.AutoDepthStencilFormat = DepthFormat.D16;</code><br>
</li><li><code>presentParams.EnableAutoDepthStencil = true;</code><br>
</li><li>Added <b>ClearFlags.ZBuffer</b> to the <b>Device.Clear</b> method call in the
<b>Render</b> method. This is to support the Depth Stencil added.<br>
</li><li>Added a speed parameter to the constructor of the <b>Tank</b> class.</li></ul>
<h2>Fonts</h2>
<p>The only feedback provided to the game player so far has been the frame rate that was displayed in the title bar of the form. We also have written out some information to the console window, but that isn't very useful when running the game as an executable.
 In addition to the frame rate, I want to be able to display the location and heading. To do this we are going to start using DirectX fonts. The example here is the simplest case of drawing text to the screen; see the Text3D sample in the DirectX SDK for a
 more extensive explanation and detailed samples.</p>
<p>The first step is to declare the variable in the <b>GameEngine</b> class. I am using a fully qualified name, so there are no namespace collisions between the Font class in the
<b>Direct3D</b> namespace and that in the <b>System.Drawing</b> namespace.</p>
<p><b>Visual C#</b></p>
<pre><code>private Microsoft.DirectX.Direct3D.Font _font;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private m_font As Microsoft.DirectX.Direct3D.Font</code></pre>
<p>Next initialize the <b>Font</b> class in the constructor of the <b>GameEngine </b>
class.</p>
<p><b>Visual C#</b></p>
<pre><code>font = new Microsoft.DirectX.Direct3D.Font(_device, 
   new System.Drawing.Font(&quot;Arial&quot;, 14.0f, FontStyle.Italic));</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_font = New Microsoft.DirectX.Direct3D.Font(m_device, 
   New System.Drawing.Font(&quot;Arial&quot;, 14.0F, FontStyle.Italic))</code></pre>
<p>The parameters should be self explanatory. Note that the DirectX <b>Font</b> class uses a Drawing
<b>Font</b> class in its constructor.</p>
<p>All of the functionality to draw the various values to the screen is encapsulated in the
<b>RenderFonts</b> method of the <b>GameEngine</b> class. This class uses the <b>
DrawText</b> method of the <b>Font</b> class to actually render the text to the screen.</p>
<p><b>Visual C#</b></p>
<pre><code>private void RenderFonts()
{
    // display the heading and pitch
    _font.DrawText(null, string.Format(
        &quot;Heading={0:N000}, Pitch ={1:N000}&quot;, 
        _camera.Heading, _camera.Pitch), 
        new Rectangle(0, 0, this.Width, this.Height),
        DrawTextFormat.NoClip | DrawTextFormat.ExpandTabs |
        DrawTextFormat.WordBreak, Color.Yellow);

    // Display the Postion Direction
    _font.DrawText(null, string.Format(&quot;X={0}, Y={1}, Z={2}&quot;,   
        _camera.Position.X, _camera.Position.Y, _camera.Position.Z), 
        new Rectangle(0, 20, this.Width, this.Height),
        DrawTextFormat.NoClip | DrawTextFormat.ExpandTabs |  
        DrawTextFormat.WordBreak, Color.Yellow);

    // Display the frame rate
    _font.DrawText(null, string.Format(&quot;FPS={0}&quot;, 
        FrameRate.CalculateFrameRate()), 
        new Rectangle(0, 60,this.Width, this.Height),
        DrawTextFormat.NoClip | DrawTextFormat.ExpandTabs | 
        DrawTextFormat.WordBreak, Color.Yellow);

    // display Lighting state
    _font.DrawText(null, string.Format(&quot;Lights={0}&quot;, 
        _lightOn ? &quot;On&quot; : &quot;Off&quot;), 
        new Rectangle(this.Width - 110, 0,this.Width, this.Height),
        DrawTextFormat.NoClip | DrawTextFormat.ExpandTabs | 
        DrawTextFormat.WordBreak, Color.Yellow);
}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private Sub RenderFonts()

        ' display the heading and pitch
        m_font.DrawText(Nothing, String.Format(
            &quot;Heading={0:N000}, Pitch ={1:N000}&quot;, 
            m_camera.Heading, m_camera.Pitch), 
            New Rectangle(0, 0, Me.Width, Me.Height), 
            DrawTextFormat.NoClip Or DrawTextFormat.ExpandTabs Or 
            DrawTextFormat.WordBreak, Color.Yellow)

        ' Display the Postion Direction
        m_font.DrawText(Nothing, String.Format(
            &quot;X={0}, Y={1}, Z={2}&quot;, m_camera.Position.X,
            m_camera.Position.Y, m_camera.Position.Z), 
            New Rectangle(0, 20, Me.Width, Me.Height),
            DrawTextFormat.NoClip Or DrawTextFormat.ExpandTabs Or
            DrawTextFormat.WordBreak, Color.Yellow)

        ' Display the frame rate
        m_font.DrawText(Nothing, String.Format(
            &quot;FPS={0}&quot;, FrameRate.CalculateFrameRate()), 
            New Rectangle(0, 60, Me.Width, Me.Height),
            DrawTextFormat.NoClip Or DrawTextFormat.ExpandTabs Or
            DrawTextFormat.WordBreak, Color.Yellow)

        ' display Lighting state
        If m_lightOn = True Then
            m_font.DrawText(Nothing, &quot;Lights=On&quot;, 
                New Rectangle(Me.Width - 110, 0, Me.Width, Me.Height),
                DrawTextFormat.NoClip Or DrawTextFormat.ExpandTabs Or
                DrawTextFormat.WordBreak, Color.Yellow)
        Else
            m_font.DrawText(Nothing, &quot;Lights=Off&quot;, 
                New Rectangle(Me.Width - 110, 0, Me.Width, Me.Height),
                DrawTextFormat.NoClip Or DrawTextFormat.ExpandTabs Or
                DrawTextFormat.WordBreak, Color.Yellow)
        End If

    End Sub</code></pre>
<p>The first two calls to the <b>DrawText</b> method of the <b>GameEngine</b> class add the heading and pitch information and position of the camera. These two pieces of information now allow me to properly orient myself in the 3D world. The last two items
 add the frame rate counter (I removed the one in the title of the form) and a lighting state indicator that is useful when experimenting with lighting.
</p>
<p>The location of the text on the screen is determined by the <b>Rectangle</b> class. The first two values determine where the upper left hand corner of the rectangle is (in screen coordinates), while the last two determine the size of the rectangle.</p>
<h2>Lighting</h2>
<p>Up to this point we have turned lighting off by setting the <b>Lighting</b> property of the
<b>RenderState</b> to <b>false</b>. This means that every object vertex is drawn solely based on its defined color. Turning lighting on adjusts the color of each vertex by combining:
</p>
<ul>
<li>Its current Material color<br>
</li><li>Texels in associated texture maps<br>
</li><li>Diffuse and Specular colors<br>
</li><li>Color and intensity of all lights in the scene, including the ambient light</li></ul>
<p>DirectX breaks light into two groups: </p>
<ol>
<li><b>Ambient</b>: Ambient light is a special type of light that has been scattered so much that it no longer has a direction or source. Ambient light illuminates equally in every direction. For ambient light you can only define color and intensity. Ambient
 light does not contribute to specular reflection and the level of ambient light is independent of any other lights in the scene. Ambient light is the least expensive (in terms of computational needs) of all the lights. Without ambient light, objects in the
 shadows would be completely black. In DirectX ambient light is implemented in the Device
<b>RenderState</b>.<br>
<br>
</li><li><b>Directional</b>: As is implied in the name, directional light has a specified direction in addition to a color and intensity. When direct light is reflected it does not contribute to the ambient light level of the scene, but it is used to compute specular
 highlights. Directional lights are represented by three types of lights which are added to the
<b>Lights</b> array of the <b>Device</b>. In DirectX, direction is the distance from the logical origin, regardless of the position of the light in the scene. A direction vector of (0,0,1) points straight into the scene and a direction vector of (0,-1,0) points
 straight down. You can also create angles by mixing and matching the values in the direction vector.
<ul>
<li><b>Directional</b>. This is a light source that has no position and produces light that travels parallel in one direction. In games, the sun and the moon are most often modeled as directional lights. Directional lights are relatively inexpensive but should
 be used in moderation, as adding many of them will negatively impact your frame rate.
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_1.gif" border="0">
</p>
</li><li><b>Point</b>. A Point light has a position and radiates light equally in all directions. Examples of point lights are bare light bulbs and torches. Point lights are more expensive than directional lights. Unlike Directional lights, a point light has an
 attenuation (how the light level decreases over distance) and a range (the maximum distance the light will travel).
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_2.gif" border="0">
</p>
</li><li><b>Spot</b>. A spot light is like a flashlight or car headlight. It is the most complex and expensive of all the light types. A spot light has a position and a direction. The light is separated by intensity into two cones: in the inner cone the light shines
 more brightly than in the outer cone. Only objects that fall within the cone (theta) are illuminated. In addition to defining the position, direction, range and attenuation of the light, you also must define the cone size and amount of falloff between the
 cones.
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_3.gif" border="0">
</p>
</li></ul>
</li></ol>
<h2>Materials</h2>
<p>In the last article we briefly touched on materials. Materials define how lights reflect off a surface. For each material in DirectX you can set properties that define how it reflects ambient, diffuse and specular light.
</p>
<p><b>Normal: </b>For all this lighting stuff to work, DirectX has to know the vector normal for each face of the object (a cube would have 6 faces). A normal is nothing other than a vector that points away from the face at a 90 degree angle. (Check out the
 managed SDK documentation, as it has an excellent description of a normal. Go to Introducing DirectX 9.0 &gt; Direct3D Graphics &gt; Getting Started with Direct3D &gt; 3-D coordinate Systems and Geometry &gt; Face and Vertex Normal Vectors.)</p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_4.gif" border="0"></p>
<h2>Color</h2>
<p>DirectX describes color in terms of four components: Red, Green, Blue and Alpha (RGBA). The values of these components can range from 0.0f to 1.0f. While both materials and lights use the same color structure, they use color differently.</p>
<p>For lights, the color values are the amount of light emitted by that color component. A value of 0.0f means that the component is turned off and a value of 1.0 means that it is at max brightness. The Alpha value is not used. You can also set the value to
 a number higher than 1.0f to create a very bright light or to a negative number to create a light that actually removes light from a scene.</p>
<p>For materials, the color values are the amount of light that is reflected by a surface. A value of 0.0f means that no light for that component is reflected and a value of 1.0f means that all light is reflected for that component.</p>
<h2>Color Types</h2>
<p>Each type of light can emit four colors. The color of the light interacts with the counterpart in the material to produce the final color used to render the object: e.g. the diffuse color of the light interacts only with the diffuse property of the material.
</p>
<ol>
<li><b>Ambient</b>: Ambient light is the general background light and is the same everywhere in the scene.<br>
</li><li><b>Diffuse</b>: Diffuse light is scattered but still maintains an overall direction. A diffuse surface reflects incoming lights across all angles; this causes the material to look dull or matte.<br>
</li><li><b>Specular</b>: This is the opposite of Diffuse. Specular light is not scattered at all and makes a surface appear reflective. To use specular lighting you must first enable it at the Device Render State.<br>
</li><li><b>Emissive</b>: DirectX also has the principle of Emissive light. This is light that is emitted by objects. Emissive light is not cast onto other objects.</li></ol>
<p>Now enough with the theory, and on to the code.</p>
<h2>Adding Lights</h2>
<p>The first step is to change the <b>RenderState.Lighting</b> property to <code>
true</code>. You can also remove the line entirely, since <code>true</code> is the default value. If you forget this step, then no lights will show regardless of how many lights are enabled. We do this in the
<b>ConfigureDevice</b> method, since this is a global setting. </p>
<p>At the bottom of the <b>ConfigureDevice</b> method, add the following code:</p>
<p><b>Visual C#</b></p>
<pre><code>_device.RenderState.Lighting = true;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_device.RenderState.Lighting = True</code></pre>
<p>Each scene can only contain a single ambient light, but multiple lights of the other three types. For this reason the Ambient light is implemented at the
<b>RenderState</b> level while the other lights are stored in the <b>Lights</b> array of the Device class. For BattleTank2005 we add some ambient white light.</p>
<p>At the bottom of the <b>ConfigureDevice</b> method, add the following code immediately after the previous added line of code:</p>
<p><b>Visual C#</b></p>
<pre><code>_device.RenderState.Ambient = Color.White;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_device.RenderState.Ambient = Color.White</code></pre>
<p>Most modern graphics cards support advanced lighting techniques, such as directional lights, and up to 8 simultaneous active lights (but you can define as many lights as you want and then turn them on/off depending on the scene). The
<b>DeviceCaps.MaxActiveLights</b> property of the <b>Device</b> determines the exact number. If the value is zero, you can not use any lights and must default to ambient lighting only. You can also query the graphics card to see how many other lights it supports,
 and then adjust your lighting strategy accordingly.</p>
<p>Add a method called <b>CreateLights</b> to the <b>GameEngine</b> class with the following code:</p>
<p><b>Visual C#</b></p>
<pre><code>if ( _device.DeviceCaps.MaxActiveLights == 0 )
{
    _device.RenderState.Ambient= Color.White;
}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>If m_device.DeviceCaps.MaxActiveLights = 0 Then
    m_device.RenderState.Ambient = Color.White
End If</code></pre>
<p>For BattleTank2005 we are going to add just one directional light to simulate the sun. In the
<b>CreateLights</b> method add the following code.</p>
<p><b>Visual C#</b></p>
<pre><code>else
{
    if ( _device.DeviceCaps.MaxActiveLights &gt; 1 )
    {
        // This directional Light is our &quot;sun&quot;
        _device.Lights[0].Type = LightType.Directional;
        // Point the light straight down
        _device.Lights[0].Direction = new Vector3( 0f, -1.0f, 0f);
        _device.Lights[0].Diffuse = System.Drawing.Color.LightYellow;
        _device.Lights[0].Enabled = true;
    }
}
</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Else
    If m_device.DeviceCaps.MaxActiveLights &gt; 1 Then
        ' This directional Light is our &quot;sun&quot;
        m_device.Lights(0).Type = LightType.Directional
        ' Point the light down
        m_device.Lights(0).Direction = New Vector3(0.0F, -1.0F, 0.0F)
        m_device.Lights(0).Diffuse = System.Drawing.Color.White
        m_device.Lights(0).Enabled = True
    End If
End If</code></pre>
<p>The last step is to call this method. Add the following code to the constructor of the
<b>GameEngine</b> class immediately after the call to <b>CreateTanks</b>.</p>
<pre><code>CreateLights ( );</code></pre>
<p>One other change to make is to turn off the lights when rendering the skybox so it remains unaffected by any light settings. In the
<b>Render</b> method of the Skybox class, add the following code immediately after the code disabling the Z-Buffer.</p>
<p><b>Visual C#</b></p>
<pre><code>_device.RenderState.Lighting = false;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_device.RenderState.Lighting = False</code></pre>
<p>After rendering the skybox we need to make sure to turn the lights back on. Add the following code immediately after the code enabling the Z-buffer.</p>
<p><b>Visual C#</b></p>
<pre><code>_device.RenderState.Lighting = true;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_device.RenderState.Lighting = True</code></pre>
<p>That's all we need to add lighting. The best way to really understand lighting and materials is seeing them in action. Go ahead and add some of the other light types to the game, or change the materials and see what happens when you manipulate the RGBA values.</p>
<h2>Adding Terrain</h2>
<p>Have you ever noticed how most games are set in space or indoors? The reason is that creating realistic looking outdoor terrain, without bringing the game to a grinding halt, is very difficult.</p>
<p>Terrain creation is an extensive subject to cover. Some developers specialize in nothing else, so have developed incredibly refined algorithms and methods to display the most realistic terrain, using the least amount of resources. While it is not possible
 to cover all the methods available, I do want to try to give you an understanding of the basics so that you can enhance Battletank2005 with more a refined technique of your choosing.
</p>
<h3>Height Map</h3>
<p>A terrain starts out as a regular grid mesh. In a regular grid mesh, all the points are equally distant from one another. Each point consists of its X,Z location and a Y value to express the height of the terrain at that point. If we were to create a simple
 3x3 terrain the grid would look like this.</p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_5.gif" border="0"></p>
<p>This simple 3x3 terrain consists of 18 triangles (or 9 quads) and it takes 36 vertices to define the points required to draw the 18 triangles. These numbers are important to understand because we will use them extensively in creating the terrain.</p>
<p>The easiest way to store the height data is in a height map represented by a grayscale image. Each pixel in the image represents one point in the grid with the height information represented by the gray scale values. Darker colors are lower elevations and
 lighter colors are higher elevations. Since the number of shades of gray is 256 (0-255) we can represent 256 distinct height values.</p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_6.gif" width="485" border="0"></p>
<p><b>Sample Height map</b></p>
<p>Most applications use the RAW format, which is basically a linear array of bytes. You can think of a RAW file as an image file with the header and footer information stripped out. Loading the height data from a RAW file is much faster than loading it from
 an image file. I have included methods for both in the code, so you can experiment with them and see for yourself. The big advantage in using an image file over a RAW file is that you can see the heightmap. You can also export image files to a RAW file using
 a number of free conversion utilities available if you use a program like <a href="http://hme.sourceforge.net/">
HME</a> or <a href="http://www.planetside.co.uk/">Terragen</a> to create the height map.
</p>
<p>In addition to creating the heightmap manually, you can use algorithms such as Fault Formation or Midpoint Displacement to create them programmatically. This approach would be useful if you include a terrain generator with your game or if you want to support
 a large number of random terrain setups.</p>
<p>Regardless how you choose to create or load your height information, the entire process of starting with a height map and ending up with a realistic-looking 3D terrain involves the following steps:
</p>
<ol>
<li>Load the height information from the height map into an array.<br>
</li><li>Store the vertices for the regular grid mesh in a vertex buffer.<br>
</li><li>Store the indexes for the regular grid mesh in an index buffer.<br>
</li><li>Compute the normals for each triangle.<br>
</li><li>Render the vertices as a triangle strip.</li></ol>
<h3>Terrain Class</h3>
<p>To represent the terrain in BattleTank2005, I added a terrain class. This class will encapsulate all terrain-related logic. The terrain class will be initialized in the constructor and rendered in the regular render loop. To render the terrain we are going
 to use a single TriangleStrip, a Vertex Buffer and Index Buffer.</p>
<p>The first step is to actually load the height data into memory. The code also contains the method for loading this data from an image, but the preferred method is to load the data from a RAW file.</p>
<p><b>Visual C#</b></p>
<pre><code>public void LoadHeightMapFromRAW ( string fileName )
{
    _isHeightMapRAW = true;
    _elevations = null;
  
    using ( Stream stream = File.OpenRead ( fileName ) )
    {
        _elevationsRAW = new byte[(int)stream.Length];
        stream.Read ( _elevationsRAW, 0, (int)stream.Length );
        ComputeValues ( (int)Math.Sqrt( (double)stream.Length ), 
                        (int)Math.Sqrt( (double)stream.Length ));
    }

    // Now load the buffers
    LoadVertexBuffer ( );
            
    LoadIndexBuffer ( );
}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Public Sub LoadHeightMapFromRAW(ByVal fileName As String)
        m_isHeightMapRAW = True
        _elevations = Nothing

        Dim stream As New FileStream(fileName, FileMode.Open)
        _elevationsRAW = New Byte(stream.Length) {}
        stream.Read(_elevationsRAW, 0, CType(stream.Length, Integer))

        ComputeValues(CType(Math.Sqrt(CType(stream.Length, Double)),
        Integer), CType(Math.Sqrt(CType(stream.Length, Double)), Integer))

        ' Now load the buffers
        LoadVertexBuffer()
        LoadIndexBuffer()
End Sub</code></pre>
<p>The first two lines are only present to support loading height data from both format types. The meat of the method is the
<b>stream.Read</b> method. This method copies the content of the stream buffer into the elevation buffer byte array. Accessing the stream inside of the using statement ensures that the stream is properly closed and disposed.</p>
<p>Once the data has been loaded, we use the length of the stream to compute the various values that we will need for terrain generation.</p>
<p><b>Visual C#</b></p>
<pre><code>private void ComputeValues ( int width, int height )
{
    // Vertices
    _numberOfVerticesX = width;
    _numberOfVerticesZ = height;
    _totalNumberOfVertices = _numberOfVerticesX * _numberOfVerticesZ;

    // Quads
    _numberOfQuadsX = _numberOfVerticesX - 1;
    _numberOfQuadsZ = _numberOfVerticesZ - 1;
    _totalNumberOfQuads  = _numberOfQuadsX * _numberOfQuadsZ;

    _totalNumberOfTriangles = _totalNumberOfQuads * 2;
    _totalNumberOfIndicies = _totalNumberOfQuads * 6;
}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code> Private Sub ComputeValues(ByVal width As Integer, 
    ByVal height As Integer)

        ' Vertices
        _numberOfVerticesX = width
        _numberOfVerticesZ = height
        _totalNumberOfVertices = _numberOfVerticesX * _numberOfVerticesZ

        ' Quads
        _numberOfQuadsX = _numberOfVerticesX - 1
        _numberOfQuadsZ = _numberOfVerticesZ - 1
        _totalNumberOfQuads = _numberOfQuadsX * _numberOfQuadsZ

        _totalNumberOfTriangles = _totalNumberOfQuads * 2
        _totalNumberOfIndicies = _totalNumberOfQuads * 6

    End Sub</code></pre>
<p>Once the height data has been loaded and the various dimensions computed, we can populate the vertex buffer.
</p>
<p><b>Visual C#</b></p>
<pre><code>   private void LoadVertexBuffer ( )
{
    // This is the buffer we are going to store the vertices in
    _vb = new VertexBuffer ( typeof(CustomVertex.PositionNormalTextured),  
        _totalNumberOfVertices, _device, Usage.WriteOnly, 
        CustomVertex.PositionNormalTextured.Format, Pool.Managed );
            
    // All the vertices are stored in a 1D array
    _vertices = new CustomVertex.PositionNormalTextured[
       _totalNumberOfVertices];
            
    // Load vertices into the buffer one by one
    for ( int z = 0; z &lt; _numberOfVerticesZ; z&#43;&#43; )
    {
        for ( int x = 0; x &lt; _numberOfVerticesX; x&#43;&#43; )
        {
            CustomVertex.PositionNormalTextured vertex;
            vertex.X = x;
            vertex.Z = z;
            
            // Set the Y to the elevation value in the elevation array
            if ( _isHeightMapRAW )
            vertex.Y = (float)_elevationsRAW[ 
               ( z * _numberOfVerticesZ ) &#43; x];
            else
            vertex.Y = _elevations[x,z];
            
            // Set the u,v values so one texture covers the entire terrain
            vertex.Tu = (float)x / _numberOfQuadsX;
            vertex.Tv = (float)z / _numberOfQuadsZ;
            
            // Set up a bogus normal
            vertex.Nx = 0;
            vertex.Ny = 1;
            vertex.Nz = 0;
            
            // Add it to the array
            // Note: this is the same formula used in the elevations 
            //computation
            // to map the 2D array coordaintes into a 1D array
            _vertices[ (  z * _numberOfVerticesZ ) &#43; x ] = vertex;
        }
    }
    
    // No overide the bogus normal computations with a real one
    ComputeNormals ( );
    
    // finally set assign the vertices array to the buffer
    _vb.SetData ( _vertices, 0, LockFlags.None );
}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private Sub LoadIndexBuffer()
    Dim numIndices As Integer = (_numberOfVerticesX * 2) *     
                (_numberOfQuadsZ) &#43; _numberOfVerticesZ - 2
    _indices = New Integer(numIndices) {}
    _ib = New IndexBuffer(GetType(Integer), _indices.Length, _device,
        Usage.WriteOnly, Pool.Managed)
    Dim index As Integer = 0
    Dim z As Integer = 0
    While z &lt; _numberOfQuadsZ
        If z Mod 2 = 0 Then
            Dim x As Integer
            x = 0
            x = 0
            While x &lt; _numberOfVerticesX
              _indices(System.Math.Min(
                  System.Threading.Interlocked.Increment(index), 
                  index - 1)) = x &#43; (z * _numberOfVerticesX)
              _indices(System.Math.Min(
                  System.Threading.Interlocked.Increment(index), 
                  index - 1)) = x &#43; (z * _numberOfVerticesX) &#43; 
                  _numberOfVerticesX
                                                    
              System.Math.Min(System.Threading.Interlocked.Increment(x), 
                  x - 1)
            End While
            If Not (z = _numberOfVerticesZ - 2) Then
               _indices(System.Math.Min(
                   System.Threading.Interlocked.Increment(index), 
                   index - 1)) = System.Threading.Interlocked.Decrement(x)
                   &#43; (z * _numberOfVerticesX)
            End If
        Else
            Dim x As Integer
            x = _numberOfVerticesX - 1
            x = _numberOfVerticesX - 1
            While x &gt;= 0
                _indices(System.Math.Min(
                    System.Threading.Interlocked.Increment(index), 
                    index - 1)) = x &#43; (z * _numberOfVerticesX)
                _indices(System.Math.Min(
                    System.Threading.Interlocked.Increment(index), 
                    index - 1)) = x &#43; (z * _numberOfVerticesX) 
                    &#43; _numberOfVerticesX
                System.Math.Max(System.Threading.Interlocked.Decrement(x), 
                    x &#43; 1)
            End While
            If Not (z = _numberOfVerticesZ - 2) Then
                _indices(System.Math.Min(
                    System.Threading.Interlocked.Increment(index),
                    index - 1)) = 
                    System.Threading.Interlocked.Increment(x) &#43; 
                    (z * _numberOfVerticesX)
            End If
        End If
        System.Math.Min(System.Threading.Interlocked.Increment(z), z - 1)
    End While
    _ib.SetData(_indices, 0, 0)
End Sub</code></pre>
<p>This method loops over the dimensions of the terrain and creates a vertex for each point, consisting of the X, Z coordinates and the height information (Y) for each point. At this stage we do not actually compute the normal, since we are going to average
 the vector values of the neighboring vertices later on and need the entire buffer to do so.</p>
<p>The <b>Tu</b> and <b>Tv</b> values determine how the Texture for the landscape is applied to the vertex. You can think of the
<b>Tu</b> and <b>Tv</b> values as the X and Y values respectively of the texture. The values are floating-point values in the range of 0.0 to 1.0. A pair of
<b>u.v</b> coordinates is called a Texel. We will cover textures and terrain in more detail in the next article. Right now we are just covering the terrain using a single terrain texture. (Actually, we are using the bottom of the skybox to do so; this ensures
 that the terrain matches the skybox closely.)</p>
<p>Now that we have the entire vertex buffer, we can go back and compute the normal for each vertex.</p>
<p><b>Visual C#</b></p>
<pre><code>private void ComputeNormals ( )
{
    // compute normals
    for ( int z = 1; z &lt; _numberOfQuadsZ; z &#43;&#43;)
    {
        for ( int x = 1; x &lt; _numberOfQuadsX; x 

&#43;&#43;)
        {
            // Use the adjoing 

vertices along both axis to compute the new 
            //normal
            Vector3 X = Vector3.Subtract ( 
                _vertices[ z * _numberOfVerticesZ &#43; x &#43; 1 ].Position, 
                _vertices[  z *_numberOfVerticesZ &#43; x - 1].Position );
            Vector3 Z = Vector3.Subtract ( 
                _vertices[ (z&#43;1) * _numberOfVerticesZ &#43; x ].Position, 
                _vertices[(z-1)*_numberOfVerticesZ&#43;x].Position );
            Vector3 Normal = Vector3.Cross ( Z, X );
            Normal.Normalize();
            _vertices[ ( z *_numberOfVerticesZ ) &#43; x].Normal = Normal;
        }
    }
}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private Sub ComputeNormals()
    ' compute normals
    Dim z As Integer = 1
    While z &lt; _numberOfQuadsZ
        Dim x As Integer = 1
        While x &lt; _numberOfQuadsX
            ' Use the adjoing vertices along both axis to 
            ' compute the new normal
            Dim VX As Vector3 = Vector3.Subtract(
                _vertices(z * _numberOfVerticesZ &#43; x &#43; 1).Position,
                _vertices(z * _numberOfVerticesZ &#43; x - 1).Position)
            Dim VZ As Vector3 = Vector3.Subtract(_vertices((z &#43; 1) *
                _numberOfVerticesZ &#43; x).Position, _vertices((z - 1) *
                _numberOfVerticesZ &#43; x).Position)
            Dim Normal As Vector3 = Vector3.Cross(VZ, VX)
            Normal.Normalize()
            _vertices((z * _numberOfVerticesZ) &#43; x).Normal = Normal
            x = x &#43; 1
        End While
        z = z &#43; 1
    End While</code></pre>
<p>We simply use the two neighboring values along the X and Z axes to compute an average normal for the vertex.
</p>
<p><b>Note</b>&nbsp;&nbsp;&nbsp;If you are just dying to go into detail for normal computations, read this paper:
<a href="http://www.gamedev.net/reference/articles/article2264.asp">http://www.gamedev.net/reference/articles/article2264.asp</a>.</p>
<p>After creating the vertex buffer, we need to create the index buffer. Index buffers are a DirectX mechanism for sharing vertex data by storing the indices into vertex buffers. Basically, they are a way to store information more efficiently. (Go to Introducing
 DirectX 9.0 &gt; Direct3D Graphics &gt; Getting Started with Direct3D &gt; Direct3D Rendering &gt; Rendering Primitives &gt; Rendering from Vertex and Index Buffers in the DirecxtX managed SDK for an excellent discussion of vertex and index buffers.)</p>
<p>In terrain creation, the large number of vertices makes the use of index buffers essential for good performance.
</p>
<p><b>Visual C#</b></p>
<pre><code>private void LoadIndexBuffer ( )
{
    int numIndices = (_numberOfVerticesX * 2) * (_numberOfQuadsZ) &#43; 
                     (_numberOfVerticesZ - 2);
    
    _indices = new int[numIndices];

    _ib = new IndexBuffer ( typeof( int ), _indices.Length, 
        _device, Usage.WriteOnly, Pool.Managed );

    int index = 0;

    for ( int z = 0; z &lt; _numberOfQuadsZ; z&#43;&#43; )
    {
        if ( z % 2 == 0 )
        {
            int x;
            for ( x = 0; x &lt; _numberOfVerticesX; x&#43;&#43; )
            {
                _indices[index&#43;&#43;] = x &#43; (z * _numberOfVerticesX);
                _indices[index&#43;&#43;] = x &#43; (z * _numberOfVerticesX) &#43; 
                                    _numberOfVerticesX;
            }
            if ( z != _numberOfVerticesZ - 2)
            {
                _indices[index&#43;&#43;] = --x &#43; (z * _numberOfVerticesX);
            }
        }
        else
        {
            int x;
            for ( x = _numberOfVerticesX - 1; x &gt;= 0; x-- )
            {
                _indices[index&#43;&#43;] = x &#43; (z * _numberOfVerticesX);
                _indices[index&#43;&#43;] = x &#43; (z * _numberOfVerticesX) &#43; 
                                    _numberOfVerticesX;
            }
            if ( z != _numberOfVerticesZ - 2)
            {
                _indices[index&#43;&#43;] = &#43;&#43;x &#43; (z * _numberOfVerticesX);
            }
        }
    } 
    _ib.SetData( _indices, 0, 0 );
}</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private Sub LoadIndexBuffer()
    Dim numIndices As Integer = (_numberOfVerticesX * 2) * 
    (_numberOfQuadsZ) &#43; _numberOfVerticesZ - 2
    _indices = New Integer(numIndices) {}
    _ib = New IndexBuffer(GetType(Integer), 
        _indices.Length, 
        _device, Usage.WriteOnly, 
        Pool.Managed)

    Dim index As Integer = 0
    Dim z As Integer = 0
    While z &lt; _numberOfQuadsZ
        If z Mod 2 = 0 Then
            Dim x As Integer
            x = 0
            x = 0
            While x &lt; _numberOfVerticesX
                _indices(System.Math.Min(
                    System.Threading.Interlocked.Increment(index), 
                    index - 1)) = x &#43; (z * _numberOfVerticesX)
                _indices(System.Math.Min(
                    System.Threading.Interlocked.Increment(index), 
                    index - 1)) = x &#43; (z * _numberOfVerticesX) 
                    &#43; _numberOfVerticesX

                System.Math.Min(System.Threading.Interlocked.Increment(x),
                    x - 1)
            End While
            If Not (z = _numberOfVerticesZ - 2) Then
                _indices(System.Math.Min(
                System.Threading.Interlocked.Increment(index), 
                index - 1)) = System.Threading.Interlocked.Decrement(x) 
                &#43; (z * _numberOfVerticesX)
            End If
        Else
            Dim x As Integer
            x = _numberOfVerticesX - 1
            x = _numberOfVerticesX - 1
            While x &gt;= 0
                _indices(System.Math.Min(
                   System.Threading.Interlocked.Increment(index), 
                   index - 1)) = x &#43; (z * _numberOfVerticesX)
                _indices(System.Math.Min(
                   System.Threading.Interlocked.Increment(index), 
                   index - 1)) = x &#43; (z * _numberOfVerticesX) 
                   &#43; _numberOfVerticesX
                System.Math.Max(System.Threading.Interlocked.Decrement(x),
                    x &#43; 1)
            End While
            If Not (z = _numberOfVerticesZ - 2) Then
                _indices(System.Math.Min(
                    System.Threading.Interlocked.Increment(index),
                    index - 1)) =System.Threading.Interlocked.Increment(x) 
                    &#43; (z * _numberOfVerticesX)
            End If
        End If
        System.Math.Min(System.Threading.Interlocked.Increment(z), z - 1)
    End While
    _ib.SetData(_indices, 0, 0)

End Sub</code></pre>
<p>Building the index buffer is probably the most difficult to understand, and there are multiple ways of doing this. The method shown here builds a single
<b>TriangleStrip</b> in a snake-like motion from the bottom to the top. Even rows are built left-to-right and odd rows right-to-left.</p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_7.gif" border="0"></p>
<p>The tricky part is moving from the last triangle in the row to the next row up. If we go straight up and the next vertex is not in line, then we end up with an extra triangle at the end. To suppress this extra triangle, we render a degenerate triangle (a
 triangle with no volume) by simply repeating the last vertex in each row. Since each adjoining triangle has the opposite winding, we have to repeat the vertex once more, otherwise the triangle would be considered back-facing and not rendered.
</p>
<p>If you don't understand this at first, don't worry; neither did I. Play with the
<b>VertexBuffer</b> and <b>IndexBuffer</b> creation methods using a small grid (like 3x3) to see the vertices and plot them one by one on paper creating the
<b>TriangleStrip</b> by hand.</p>
<p>The last step is to provide a way to render the terrain.</p>
<p><b>Visual C#</b></p>
<pre><code>public void Render ( )
{
    _device.Material = _material;

    // Adjust the unit to the selected scale
    _device.Transform.World = Matrix.Scaling ( 1.0f, 0.3f, 1.0f );
    _device.SetTexture ( 0, _terrainTexture );
    _device.Indices = _ib;
    _device.SetStreamSource ( 0, _vb, 0 );
    _device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
    _device.DrawIndexedPrimitives ( PrimitiveType.TriangleStrip, 0, 0,
        _totalNumberOfVertices, 0, _indices.Length - 2 );
}
</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Public Sub Render()

    _device.Material = _material

    ' Adjust the unit to the selected scale
    _device.Transform.World = Matrix.Scaling(1.0F, 0.3F, 1.0F)
    _device.SetTexture(0, _terrainTexture)
    _device.Indices = _ib
    _device.SetStreamSource(0, _vb, 0)
    _device.VertexFormat = CustomVertex.PositionNormalTextured.Format
    _device.DrawIndexedPrimitives(PrimitiveType.TriangleStrip, 0, 0,
        _totalNumberOfVertices, 0, _indices.Length - 2)

End Sub</code></pre>
<p>This code should look very familiar from the earlier articles. The main difference between this render call and previous ones is the use of the index buffer and the corresponding
<b>DrawIndexedPrimitives</b> call. We are also using the scaling matrix to make the terrain less hilly by scaling it down on the Y axis. You can also scale it up on the Z and X axis to get a larger terrain without having to load in a larger height map.</p>
<p>To integrate the terrain class into the game, we need to add a variable to the
<b>GameEngine</b> class.</p>
<p><b>Visual C#</b></p>
<pre><code>private Terrain 

_terrain;</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>Private m_terrain 

As Terrain</code></pre>
<p>Then we initialize the <b>Terrain</b> class and call the appropriate <b>LoadHeightMap</b> method in the constructor of the
<b>GameEngine</b> class.</p>
<p><b>Visual C#</b></p>
<pre><code>_terrain = new Terrain ( &quot;Down.jpg&quot;, this._device );
_terrain.LoadHeightMapFromRAW ( &quot; Heightmap256.raw&quot; );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>m_terrain = New Terrain(&quot;Down.jpg&quot;, m_device)
m_terrain.LoadHeightMapFromRAW(&quot;Heightmap256.raw&quot;)</code></pre>
<p>And finally we add the <b>Terrain</b> class to the <b>Render</b> loop.</p>
<p><b>Visual C#</b></p>
<pre><code>_terrain.Render (  );</code></pre>
<p><b>Visual Basic</b></p>
<pre><code>_terrain.Render (  );</code></pre>
<p>The finished result should look something like the picture below. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_8.gif" target="_Top"><img title="Click here for larger image" alt="Click here for larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_8_thumb.gif" border="0"></a></p>
<p><b>(click image to zoom)</b></p>
<p>In this particular picture I am rendering in wire-frame mode, so the skybox is rendered as a simple wire-frame cube, the corner of which is visible in the bottom of this screenshot. Zooming in closer, you can clearly see the regular grid mesh with Y values.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_8.gif" target="_Top"><img title="Click here for larger image" alt="Click here for larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/1044115/beginning6_9_thumb.gif" border="0"></a></p>
<p><b>(click image to zoom)</b></p>
<p>For this version I have added support for switching among the various render modes. Press F1 to see the scene rendered in wire-frame mode, F2 to see it rendered in solid mode, and F3 to see it rendered in Point mode. I also set up the F4 and F5 keys to toggle
 the directional light on and off, so you can easily see the difference.</p>
<h2>Summary</h2>
<p>Wow! That was a lot to cover and I haven't even started talking about automatic texture mapping, height-based lighting, light-maps, Level Of Detail, ROAM, Geomipmapping, quadtrees and culling. I also still need to cover collision detection, and finally,
 I want to adjust our camera pitch, yaw and roll to conform to the underlying terrain, so the game provides a realistic &quot;driving&quot; experience. As usual, I hope you experiment with the code to gain a good understanding of the issues we just covered. Next time
 we will address more advanced terrain and cover creating and rendering issues as well as collision detection.</p>
<p>Until then: Happy coding.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:014159ac983a475cb69f9e7600d8cc8e">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VI-Lights-Materials-and-Terrain</comments>
      <itunes:summary>



&amp;nbsp;
This is Part 6 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers Lights and Materials and gives a very basic introduction to terrain.



Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
3-6 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions,
DirectX SDK
Hardware: 
Download: 


C# Download
VB Download

Beginning Game Development Series


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III








Introduction
Welcome to the sixth article on beginning game development. Last time I promised we would discuss lighting, terrain building and collision detecting in this article, but there is enough information in terrain building alone to cover multiple articles and
 the same holds true for collision detection. So instead, I am going to cover Lights and Materials and give a very basic introduction to terrain building in this article, and go into more depth about terrain building and collision detection in the next article. 
Before we start, let&#39;s do the obligatory code cleanup, incorporating all the feedback I received. 
Code cleanup
The cleanup for this article consists mainly of version upgrades and some minor performance improvements.
 

Updated to the release version of 
Visual Studio Express
Updated to the 
October 2005 DirectX SDK.
Added the following code to the ConfigureDevice method. Depth stencils enable the application to</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VI-Lights-Materials-and-Terrain</link>
      <pubDate>Thu, 09 Nov 2006 11:35:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VI-Lights-Materials-and-Terrain</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1044115_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/1044115_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>17</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VI-Lights-Materials-and-Terrain/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Beginning Game Development: Part VIII - DirectSound</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">In this article, we are going to look at another facet of DirectX, the ability to control sound devices.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b></div>
<div class="entry_details">
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/999786/BattleTankPt8_CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/999786/BattleTankPt8_VB.msi">VB Download</a></li></ul>
</div>
<div class="entry_details"><strong>Beginning Game Development Series</strong></div>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
<a class="" href="http://msdn.microsoft.com/coding4fun/gaming/arcade/article.aspx?articleid=999786&amp;title=Beginning&#43;Game&#43;Development%3a&#43;Part&#43;VIII&#43;-&#43;DirectSound"></a></td>
</tr>
</tbody>
</table>
</span>
<p>Welcome to the eighth article on beginning game development. We have spent a lot of time working with the graphics capabilities of DirectX. We also covered how the DirectX API allows us to control input devices. Now we are going to look at another facet
 of DirectX, the ability to control sound devices. This capability is found in the DirectSound and AudioVideoPlayback namespaces.</p>
<h2>Sound in Games </h2>
<p>Sound creates an ambiance in a game that provides for a more immersive game experience. Imagine how dull a game would be without sound effects; nothing would indicate when you fire your cannon or an explosion occurs. Sounds also can be used to increase the
 drama of a scene by increasing the tempo as the action increases. </p>
<p>Sound effects also provide the same audible cues we expect in real life, such as the direction and speed of a person approaching us based on the volume, direction, and frequency of the footsteps. These sound effects add realism to the game just like proper
 physical behavior of objects do (something I will cover in an upcoming article about physics). Games also provide background music to make playing the game more fun. In newer games, artists who have their music included in a sound track for a popular game
 see an upswing of sales — it is not unusual for well-known artists to provide music for a game soundtrack. In effect, games have reached the same level as movies with the regards to the importance of soundtracks.</p>
<p>In BattleTank2005 I want to integrate sound in the following way. First, I want standard sound effects for shooting, explosions, and engine noise, and I want that sound to be directionally accurate. What I mean is that when I am getting shot at by an enemy
 to my left, I want the sound to come from the left and the volume to be an indicator of the proximity of the unit.</p>
<p>Secondly, I want to be able to play background music during game play and I want to control what music plays when in the game. This means I want to have one song play during the splash screen and game setup, another while playing the game, and yet another
 during the HiScore capturing (we are going to add these screens and states in a later article).</p>
<p>I am going to cover the first requirement in this article, and then cover sound effects and playing MP3 and WMA files with the AudioVideo namespace in the next article. Before we add these features, let's review the capabilities of DirectSound.</p>
<h2>DirectSound</h2>
<p>The DirectSound namespace only supports playing 2 channel waveform audio data at fixed sampling rates (PCM). While I have no idea what that really means, it is safe to state that you should use DirectSound to play short WAV files and the AudioVideoPlayback
 namespace for longer MP3 or WMA files. I am not going to cover how to use the sound capturing/recording capabilities of DirectSound namespace — but remember that they exist so you know where to look if your game requires recording sounds as well as playing
 them.</p>
<p>The DirectSound namespace provides the ability to play and capture sound with three-dimensional positioning effects. DirectSound also provides the ability to add sound effects to the audio played or recorded. Just like in the DirectX3D and the DirectInput
 namespaces, the actual hardware device used is abstracted into a device class. Just like the device classes in those two namespaces, the DirectSound device uses buffers, has a cooperative level, and has device capabilities. I am not going to cover the sound
 effects in this article, but they are not forgotten; they will be covered in detail in the next article.</p>
<h3>Device</h3>
<p>A device is the interface to the audio hardware on the computer. You can either create a Device class using a default GUID (DSoundHelper.DefaultPlaybackDevice) or enumerate all the devices on a system. Like the other device classes, each enumerated device
 has a list of capabilities stored in a Caps structure in the <b>Caps</b> property for the device. Once you have chosen your device, you instantiate the device class using a specific GUID.</p>
<p>Audio devices also have a cooperative level like the input devices did. The three possible values are: Normal, Priority, and Write Primary. These values are set via the CooperativeLevel enumeration.</p>
<table class="" cols="cols" rules="all" width="504" border="1" frame="box">
<tbody>
<tr valign="top">
<td class="" width="148"><b>Cooperative Level</b></td>
<td class="" width="354"><b>Meaning</b></td>
</tr>
<tr valign="top">
<td class="" width="150">Normal</td>
<td class="" width="354">The application cannot set the format of, or write to, the primary buffer. For all the applications that use this level, the primary buffer setting is locked at 22 kHz, stereo, 8-bit samples.</td>
</tr>
<tr valign="top">
<td class="" width="150">Priority</td>
<td class="" width="354">Provides first rights to access hardware resources for mixing, etc., and can change the format of the primary sound buffer.
<i>This is the preferred setting for games</i>.</td>
</tr>
<tr valign="top">
<td class="" width="150">Write Primary</td>
<td class="" width="354">Provides direct access to the primary sound buffer, but the application must write directly to the primary buffer.</td>
</tr>
</tbody>
</table>
<br>
<h3>Buffers</h3>
<p>All the sounds in DirectX are controlled via buffers. These buffers can exist in the memory of the computer or on the sound card itself. The two buffers used in DirectSound are called the primary buffer and secondary buffer.
</p>
<p>The <b>primary buffer</b> contains the actual audio data that is sent to the device and is automatically created and managed by the DirectX API. The API mixes the sound in the primary buffer with any secondary buffers. If you need to interact directly with
 the primary buffer, make sure to change the Cooperative level of the device to Write Primary.</p>
<p><b>Secondary buffers</b> hold a single audio stream and must be explicitly created by the application. Each application must create at least one secondary buffer to store and play sounds. Each secondary buffer also has a specific waveform format (described
 in the WaveFormat structure), and only sound data that matches that format can be loaded into that secondary buffer. An application can play sounds of differing formats by creating a separate secondary buffer for each format and letting the API mix them into
 a common format in the primary buffer. To mix sounds in two different secondary buffers, simply play them at the same time and let the API mix them in the primary buffer. The only limitation to the number of different secondary buffers that can be mixed is
 the processing power of the system, but remember that any additional processing required will also slow down your game. We have not added any AI or physics computations, but we should be careful with the available processing power.</p>
<p>Any secondary buffer can be used for the life of the application, or it can be created and destroyed as needed. A single secondary buffer can contain the same data throughout the entire game or it can be loaded with different sounds (as long as they match
 the format). The sound in the secondary buffer can be played once or set up to loop. If the sound to be played is short, it can be loaded into the buffer in its entirety (called a static buffer), but longer sounds must be streamed. It is the responsibility
 of the application to manage the streaming of the sound to the buffer. </p>
<p>When a buffer is created you have to specify the control options for that buffer using the BufferDescription class. If you use a property of the buffer without first setting it in the control properties, an exception is thrown. The control options can be
 combined by either setting each property to true or combined in the <b>Flag</b> property.</p>
<div>
<div>
<pre><span> 1:</span> BufferDescription bufferDescription = <span>new</span> BufferDescription ( );</pre>
<pre><span> 2:</span> <span>// Use the seperate properties</span></pre>
<pre><span> 3:</span> bufferDescription.ControlVolume = <span>true</span>;</pre>
<pre><span> 4:</span> bufferDescription.ControlPan = <span>true</span>;</pre>
<pre><span> 5:</span> <span>// or combine them in the Flags property</span></pre>
<pre><span> 6:</span> bufferDescription.Flags = BufferDescriptionFlags.ControlVolume | BufferDescriptionFlags.ControlPan;</pre>
</div>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h3>Controlling Volume, Pan, and Frequency</h3>
<p>To control these settings of the buffer you must first set the <b>ControlPan, ControlVolume</b>, and
<b>ControlFrequency</b> properties of the buffer to true. You can then set the pan, volume, and frequency values using the buffer's Pan, Volume, and Frequency properties.</p>
<p><b>Volume</b> is expressed in hundredths of a decibel and ranges from 0 (full volume) to -10,000 (completely silent). The decibel scale is not linear, so you may reach effective silence well before the volume setting reaches true silence at -10,000. There
 is also no way to increase the volume of the sound above the volume it was recorded at, so you have to make sure to record the sound with a high enough volume to at least match the desired maximum volume in the game.</p>
<p><b>Pan</b> is expressed as an integer and ranges from -10,000 (full left) to &#43;10,000 (full right), with 0 being center.
</p>
<p>The <b>frequency</b> value is expressed in samples per seconds and represents the playback speed of the buffer. A larger number plays the sound faster and raises the pitch while a smaller number slows the speed down and lowers the pitch. To reset the sound
 to its original frequency, simply set the frequency value to 0. The minimum value for frequency is 100 and the maximum value is 200,000.</p>
<p>At this point you may think that we could use the volume, pan, and frequency settings to manipulate the sound and make it reflect the direction and distance of its origin. This was, after all, one of our original requirements. But instead of us performing
 the calculations to determine the relative locations and distances of each object, DirectX provides an API to do just that for us.
</p>
<h2>3D Sound</h2>
<p>The 3D features of DirectX allow us to locate sounds in space and apply Doppler shift to moving sounds.</p>
<p><b>Note</b>&nbsp;&nbsp; Check out this excellent <a href="http://en.wikipedia.org/wiki/Doppler_effect">
explanation of the Doppler effect</a> at Wikipedia, or use this <a href="http://www.lon-capa.org/~mmp/applist/doppler/d.htm">
applet</a> to help yourself to visualize what it is.</p>
<p>Before describing how DirectX handles sound in three dimensions, it is probably useful to talk about how we perceive sound. DirectX uses these same principles to make the sound appear as realistic as possible.
</p>
<ol>
<li>The volume of a sound decreases at a fixed rate as the distance to the listener increases. This effect is called Rolloff. The relationship between the volume of a sound and its distance from the listener is inverse-proportional, meaning that if the distance
 is halved the volume doubles. (See: <a href="http://en.wikipedia.org/wiki/Inverse_square_law">
http://en.wikipedia.org/wiki/Inverse_square_law</a>) <br>
<br>
</li><li>The listener perceives sounds coming from the left as louder in the left ear than the in right ear (interaural intensity difference) and also hears sounds coming from the left sooner in the left ear than the right ear (interaural time difference). (See:
<a href="http://en.wikipedia.org/wiki/Interaural_Intensity_Difference">http://en.wikipedia.org/wiki/Interaural_Intensity_Difference</a>)
<br>
<br>
</li><li>The shape of the ear produces an effect called &quot;muffling&quot;: sounds coming from the front are perceived as louder than those coming from the back. This is, of course, because the human ear is directed towards the front of the head.
<br>
<br>
</li><li>The ridges of the earlobe slightly alter the sound arriving from different directions. This provides cues to the brain about the location of the sound source. This effect can be modeled mathematically and is called the Head Related Transfer Function (HRTF).
 (See: <a href="http://en.wikipedia.org/wiki/Head_Related_Transfer_Function">http://en.wikipedia.org/wiki/Head_Related_Transfer_Function</a>)</li></ol>
<p>We already know that DirectX uses the left-handed Cartesian coordinates system and Vectors to express position and directional information. This same system is also used by DirectSound in its computations. One important piece of information when dealing
 with 3D sound is that the default unit of measurement for distance is the meter and the default measurement for velocity is meters per second. You need to make sure to use a common system of measurement in the game. You can change this by setting the
<b>DistanceFactor</b> property of the Listener3D object to a value that represents the meters per application-specified distance unit. If you have been using feet in all your calculations up to this point, simply set this value to 0.3048 (there are 0.3048 meters
 in a foot). </p>
<p>Also, since we are leaving the manipulation of the sound to DirectX (as opposed to us changing the volume, pan, and frequency), we must ensure that the sound source we are using is a mono and not stereo source. Finally, make sure to set the
<b>Control3D</b> property of the buffer to true to enable 3D sounds. </p>
<p>DirectSound uses two objects to manage 3D sounds in the application: <b>Buffer3D</b> and
<b>Listener3D</b>.</p>
<h3>3D Buffers</h3>
<p>Unlike the SecondaryBuffer, a Buffer3D object does not inherit from the Buffer class. Instead you create a 3D Buffer object by passing it a SecondaryBuffer in the constructor. The 3D Buffer exposes a number of properties that determine how the sound is processed.</p>
<p>The <b>MinDistance</b> property determines at which distance the sound volume is no longer increased. You can also use this setting to make certain sounds appear louder even if they were recorded at the same volume (see the DirectX documentation for a detailed
 explanation of this). The default value for this property is 1 meter, meaning that the sound is at full volume when the distance between the listener and the sound source equals 1 meter.</p>
<p>The <b>MaxDistance</b> property is the opposite and determines the distance after which the sound no longer decreases in volume. The default value for this property is 1 billion meters, which is well beyond hearing range anyway. To avoid unnecessary processing,
 you should set this value to a reasonable value and set the <b>Mute3DAtMaximumDistance</b> property of the BufferDescription to true.</p>
<p>Finally, we can also specify values for the sound cone if the sound is directional. A sound cone is almost identical to the cone produced by a spotlight (see article 6). It consists of a set of angles, one for the inside and one for the outside cone, and
 orientation, and an outside volume property. Check out the <a href="http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_m/directx/sound/3-dsound/directsound_3-d_buffers.asp">
DirectX documentation</a> for more detail on sound cones.</p>
<h3>3D Listeners</h3>
<p>While the 3D Buffer describes the source of a sound, the 3D Listener describes the, well, listener. Just as the position, orientation, and velocity of the buffer affects the sound, so does the position, orientation, and velocity of the listener. The default
 listener in DirectX is located at the origin pointing toward the positive z-axis, and the top of the head is along the positive y-axis. Each application can only have one Listener3D object.</p>
<p>To change the way the player hears the sound in your game, you manipulate the position, orientation, and velocity of the Listener. You can also control global settings of the acoustic environment like the Doppler shift or Rolloff factor.
</p>
<p><b>Note</b>&nbsp;&nbsp; The <b>DopplerFactor</b> and <b>RolloffFactor</b> properties are a number between 0 and 10. Zero means that the value is turned off. One represents the real world values of these acoustic effects. All other values are multiples, so that a 2
 means doubling the real world effect, 3 means tripling it, and so on.</p>
<p>In BattleTank2005 we are going to add three new classes; a SoundDevice class to represent the actual audio device, a SoundListner class to encapsulate the Listener3D object, and a SoundEffects class to represent each separate sound effect. Each tank in BattleTank2005
 can have multiple sounds associated with it, such as engine noise and the noise made when firing. To integrate sound we are going to update the Tank class to play these sounds at the appropriate time and with the appropriate position information. I did not
 add this functionality to the UnitBase class because the stationary objects (the obstacles) will not have any sounds associated with them.</p>
<p>Before we start adding these classes we need add a reference to the Microsoft.DirectX.DirectSound.DLL assembly. Make sure to choose the 1.0 and not the 2.0 version. BattleTank2005 has not yet been updated to use the beta versions of the 2.0 DirectX API.
 Add a new class called SoundDevice and add the using statement for Microsoft.DirectX.DirectSound. All three of the classes will implement the IDisposable interface and use the same Dispose pattern that we used in the Keyboard and Mouse classes. (I omitted
 that portion from the code samples below to keep them more compact and easy to understand).</p>
<p>Following the now familiar patterns we add a private variable called _device to the SoundDevice class and instantiate it in the constructor. We also need to set the CooperativeLevel before we can use the device. As discussed earlier, we will use CooperativeLevel.Priority
 setting. We also pass a reference of the game form to this method so that the device can receive Windows messages. Finally, we surround the device creation code with a Try/Catch, since things can go wrong whenever we work with devices.</p>
<pre class="csharpcode"></pre>
<div>
<div>
<pre><span> 1:</span> <span>using</span> System;</pre>
<pre><span> 2:</span> <span>using</span> Microsoft.DirectX.DirectSound;</pre>
<pre><span> 3:</span>&nbsp; </pre>
<pre><span> 4:</span> <span>namespace</span> BattleTank2005</pre>
<pre><span> 5:</span> { </pre>
<pre><span> 6:</span> <span>class</span> SoundDevice : IDisposable </pre>
<pre><span> 7:</span> { </pre>
<pre><span> 8:</span> <span>public</span> SoundDevice( System.Windows.Forms.Form parentForm ) </pre>
<pre><span> 9:</span> { </pre>
<pre><span> 10:</span> <span>try</span></pre>
<pre><span> 11:</span> {</pre>
<pre><span> 12:</span> _device = <span>new</span> Microsoft.DirectX.DirectSound.Device(); _device.SetCooperativeLevel(parentForm, CooperativeLevel.Priority); } <span>catch</span></pre>
<pre><span> 13:</span> {</pre>
<pre><span> 14:</span> <span>// Can not use sounds</span></pre>
<pre><span> 15:</span> }</pre>
<pre><span> 16:</span> }</pre>
<pre><span> 17:</span> </pre>
<pre><span> 18:</span> <span>public</span> Microsoft.DirectX.DirectSound.Device AudioDevice </pre>
<pre><span> 19:</span> { </pre>
<pre><span> 20:</span> get { <span>return</span> _device; } </pre>
<pre><span> 21:</span> } </pre>
<pre><span> 22:</span> </pre>
<pre><span> 23:</span> <span>private</span> Microsoft.DirectX.DirectSound.Device _device; </pre>
<pre><span> 24:</span> }</pre>
<pre><span> 25:</span> }</pre>
</div>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The next class we need is the SoundListener class. After adding the using statements for DirectSound and DirectX, we construct the class by passing a reference to the SoundDevice class created earlier. The Listener needs to be associated with the Primary
 Buffer of the audio card so it can &quot;hear&quot; the final mixed sounds. Even so, the SoundListener class is largely passive, so we do need to update its position, velocity, and orientation to enable 3D sounds on the buffer. Once the buffer is created we pass it
 to the constructor of the Listener3D class to create the Listener. The final step is to store the Listener3DSettings of the listener in a local variable so we can access them in the Update method.</p>
<p>The Update method provides the way in which we pass the position information to the Listener object.</p>
<p>The last step is to apply the updated values to the Listener. We do this by calling the CommitDeferredSettings method of the Listener3D class after updating the Listener3DSettings values. This method simply commits all changes made to the Listener3DSettings
 since the last time the method was called. When all is done, the SoundListener class is positioned at the correct location in the game.</p>
<pre class="csharpcode"></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<div>
<div>
<pre><span> 1:</span> <span>using</span> System;</pre>
<pre><span> 2:</span> <span>using</span> Microsoft.DirectX;</pre>
<pre><span> 3:</span> <span>using</span> Microsoft.DirectX.DirectSound;</pre>
<pre><span> 4:</span>&nbsp; </pre>
<pre><span> 5:</span> <span>namespace</span> BattleTank2005</pre>
<pre><span> 6:</span> { </pre>
<pre><span> 7:</span> <span>class</span> SoundListener : IDisposable </pre>
<pre><span> 8:</span> { </pre>
<pre><span> 9:</span> <span>public</span> SoundListener(SoundDevice soundDevice) </pre>
<pre><span> 10:</span> { </pre>
<pre><span> 11:</span> BufferDescription bufferDescription = <span>new</span> BufferDescription(); </pre>
<pre><span> 12:</span> bufferDescription.PrimaryBuffer = <span>true</span>; </pre>
<pre><span> 13:</span> bufferDescription.Control3D = <span>true</span>; </pre>
<pre><span> 14:</span> </pre>
<pre><span> 15:</span> <span>// Get the primary buffer</span></pre>
<pre><span> 16:</span> Microsoft.DirectX.DirectSound.Buffer buffer = <span>new</span> Microsoft.DirectX.DirectSound.Buffer(bufferDescription, soundDevice.AudioDevice); </pre>
<pre><span> 17:</span>&nbsp; </pre>
<pre><span> 18:</span> <span>// Attach the listener to the primary buffer</span></pre>
<pre><span> 19:</span> _listener3d = <span>new</span> Listener3D(buffer); </pre>
<pre><span> 20:</span> </pre>
<pre><span> 21:</span> <span>// Store the initial parameters</span></pre>
<pre><span> 22:</span> _listenerSettings = <span>new</span> Listener3DSettings(); </pre>
<pre><span> 23:</span> _listenerSettings = _listener3d.AllParameters; </pre>
<pre><span> 24:</span> } </pre>
<pre><span> 25:</span>&nbsp; </pre>
<pre><span> 26:</span> <span>public</span> <span>void</span> Update(Vector3 position ) </pre>
<pre><span> 27:</span> { </pre>
<pre><span> 28:</span> _listener3d.Position = position; </pre>
<pre><span> 29:</span> _listener3d.CommitDeferredSettings(); </pre>
<pre><span> 30:</span> } </pre>
<pre><span> 31:</span> </pre>
<pre><span> 32:</span> <span>private</span> Microsoft.DirectX.DirectSound.Listener3D _listener3d; </pre>
<pre><span> 33:</span> <span>private</span> Listener3DSettings _listenerSettings; </pre>
<pre><span> 34:</span> }</pre>
<pre><span> 35:</span> }</pre>
</div>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now that we have classes representing the audio device and a class to &quot;listen&quot; to the sounds, we need to actually create the sounds. For this we add the SoundEffect class. Once again we need to add the using statement for the DirectSound namespace. We also
 need to add a using statement for the DirectX namespace because we are going to use the Vector3 class.</p>
<p>A SoundEffect is created by passing a reference to the SoundDevice and a path to a WAV file containing a sound. In the constructor, we create a BufferDescription object that will &quot;turn on&quot; all of the capabilities we want. For right now we want the ability
 to control sounds in 3D, adjust the volume, and change the frequency. Next we create a secondary buffer passing in the path to the sound file and the BufferDescription we just created. To create the Buffer3D that we need to play 3D sounds, we pass the SecondaryBuffer
 to the Buffer3D class on instantiation, and voila! we have a 3DBuffer.</p>
<p>Once the Buffer3D class is set up we can access the properties and change the settings. We set the MaxDistance to a more manageable number. This setting combined with the Mute3DAtMaximumDistance setting on the SecondaryBuffer ensures that sounds too distant
 to hear are not played at all and don't consume any processing cycles.</p>
<p>To actually use the SoundEffect in the game we provide three public methods: one to play the sound one to stop the Sound (if it is looping) and one to update the class. The Play method either plays the sound once or loops the sound depending on the setting
 of the _isLooping variable. If the sound is looping, we need to be able to stop it, and that is what the Stop method does. The Update method is the way in which we pass the updated position of the tank the sound is associated with to the sound buffer so it
 can be accurately calculated.</p>
<div>
<div>
<pre><span> 1:</span> <span>using</span> System;</pre>
<pre><span> 2:</span> <span>using</span> Microsoft.DirectX.DirectSound;</pre>
<pre><span> 3:</span> <span>using</span> Microsoft.DirectX;</pre>
<pre><span> 4:</span>&nbsp; </pre>
<pre><span> 5:</span> <span>namespace</span> BattleTank2005</pre>
<pre><span> 6:</span> { </pre>
<pre><span> 7:</span> <span>public</span> <span>class</span> SoundEffects : IDisposable </pre>
<pre><span> 8:</span> { </pre>
<pre><span> 9:</span> <span>public</span> SoundEffects( SoundDevice soundDevice, <span>string</span> soundFile) </pre>
<pre><span> 10:</span> { </pre>
<pre><span> 11:</span> BufferDescription bufferDescription = <span>new</span> BufferDescription(); </pre>
<pre><span> 12:</span> bufferDescription.Control3D = <span>true</span>; </pre>
<pre><span> 13:</span> bufferDescription.ControlVolume = <span>true</span>; </pre>
<pre><span> 14:</span> bufferDescription.ControlFrequency = <span>true</span>; </pre>
<pre><span> 15:</span> bufferDescription.Mute3DAtMaximumDistance = <span>true</span>; </pre>
<pre><span> 16:</span> </pre>
<pre><span> 17:</span> <span>try</span></pre>
<pre><span> 18:</span> {</pre>
<pre><span> 19:</span> _secondaryBuffer = <span>new</span> SecondaryBuffer(soundFile, bufferDescription, soundDevice.AudioDevice); </pre>
<pre><span> 20:</span> _3dBuffer = <span>new</span> Buffer3D(_secondaryBuffer); </pre>
<pre><span> 21:</span> _3dBuffer.MaxDistance = 10000; </pre>
<pre><span> 22:</span> }</pre>
<pre><span> 23:</span> <span>catch</span></pre>
<pre><span> 24:</span> {</pre>
<pre><span> 25:</span> <span>// Can not use sounds</span></pre>
<pre><span> 26:</span> }</pre>
<pre><span> 27:</span> }</pre>
<pre><span> 28:</span> </pre>
<pre><span> 29:</span> <span>public</span> <span>void</span> Update(Vector3 position){ </pre>
<pre><span> 30:</span> _3dBuffer.Position = position; </pre>
<pre><span> 31:</span> } </pre>
<pre><span> 32:</span> </pre>
<pre><span> 33:</span> <span>public</span> <span>void</span> Play() </pre>
<pre><span> 34:</span> { </pre>
<pre><span> 35:</span> <span>if</span> (_isLooping == <span>true</span>) </pre>
<pre><span> 36:</span> _secondaryBuffer.Play(0, BufferPlayFlags.Looping); </pre>
<pre><span> 37:</span> <span>else</span></pre>
<pre><span> 38:</span> _secondaryBuffer.Play(0, BufferPlayFlags.Default);</pre>
<pre><span> 39:</span> }</pre>
<pre><span> 40:</span>&nbsp; </pre>
<pre><span> 41:</span> <span>public</span> <span>void</span> Stop() </pre>
<pre><span> 42:</span> { </pre>
<pre><span> 43:</span> _secondaryBuffer.Stop(); </pre>
<pre><span> 44:</span> _secondaryBuffer.SetCurrentPosition(0); </pre>
<pre><span> 45:</span> } </pre>
<pre><span> 46:</span> </pre>
<pre><span> 47:</span> <span>public</span> <span>bool</span> IsLooping </pre>
<pre><span> 48:</span> { </pre>
<pre><span> 49:</span> set { _isLooping = <span>value</span>; } </pre>
<pre><span> 50:</span> } </pre>
<pre><span> 51:</span>&nbsp; </pre>
<pre><span> 52:</span> <span>public</span> <span>int</span> Volume </pre>
<pre><span> 53:</span> { </pre>
<pre><span> 54:</span> set { _secondaryBuffer.Volume = <span>value</span>; } </pre>
<pre><span> 55:</span> } </pre>
<pre><span> 56:</span>&nbsp; </pre>
<pre><span> 57:</span> <span>public</span> <span>int</span> Frequency </pre>
<pre><span> 58:</span> { </pre>
<pre><span> 59:</span> set { _secondaryBuffer.Frequency = <span>value</span>; } </pre>
<pre><span> 60:</span> } </pre>
<pre><span> 61:</span>&nbsp; </pre>
<pre><span> 62:</span> <span>private</span> SecondaryBuffer _secondaryBuffer; </pre>
<pre><span> 63:</span> <span>private</span> Buffer3D _3dBuffer; </pre>
<pre><span> 64:</span> <span>private</span> <span>bool</span> _isLooping; </pre>
<pre><span> 65:</span> }</pre>
<pre><span> 66:</span> }</pre>
</div>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<pre class="csharpcode"></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now we need to integrate these new classes into the overall game. The first step is to add a private variable to the GameEngine class to hold a reference to the SoundDevice and SoundListener classes because we can only have one of each of these classes.
 At the bottom of the GameEngine class, add the following code:</p>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">private</span> SoundDevice _soundDevice;

  <br><span class="kwrd">private</span> SoundListener _soundListener;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next, we need to instantiate each class. The Initialize class of the GameEngine is the perfect spot for this, but to keep sound-related items together we will create a method called ConfigureSounds. In the GameEngine class add the following method:</p>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> ConfigureSounds()

  <br>{

  <br>_soundDevice = <span class="kwrd">new</span> SoundDevice(<span class="kwrd">this</span>);

  <br>_soundListener = <span class="kwrd">new</span> SoundListener(_soundDevice);

  <br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now add a call to the ConfigureSounds method to the Initialize method of the GameEngine right after the call to the ConfigureDevice method.</p>
<pre><code>ConfigureDevice();
    <br>ConfigureSounds()</code></pre>
<p>With regard to the SoundDevice class, this is all we have to do. After creation all we need this class for is its reference to the
<b>Device</b> object. The SoundListener class, however, needs to be updated with the correct position information in each frame. The Render method of the GameEngine class is the perfect place for this. We simply pass in the position of the camera class since
 it represents our location in the game. In the Render method of the GameEngine class, add the following code immediately after the call to the Update method of the camera.</p>
<code>_soundListener.Update(_camera.Position ); <br>
</code>
<p>Each tank gets a unique instance of the SoundEffect class for each sound it can make. First we need to add some private variables to hold the two sound effects we want the tank to make. At the bottom of the Tank class add the following code:</p>
<pre class="csharpcode"><span class="kwrd">private</span> SoundEffects _engineSound;

  <br><span class="kwrd">private</span> SoundEffects _fireSound;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<pre class="csharpcode"></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>To make sure each tank has the necessary sound we will pass them in the constructor. Update the constructor of the Tank class to look as follows (the new code is in bold):</p>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<div>
<div>
<pre><span> 1:</span> <span>public</span> Tank(Device device, <span>string</span> meshFile, Vector3 position, <span>float</span> scale, </pre>
<pre><span> 2:</span> <span>float</span> speed, SoundEffects fireSound, SoundEffects engineSound)</pre>
<pre><span> 3:</span> : <span>base</span>(device, meshFile, position, scale)</pre>
<pre><span> 4:</span> { </pre>
<pre><span> 5:</span> _speed = speed; </pre>
<pre><span> 6:</span> _engineSound = engineSound; </pre>
<pre><span> 7:</span> _engineSound.IsLooping = <span>true</span>; </pre>
<pre><span> 8:</span> _engineSound.Play(); </pre>
<pre><span> 9:</span> _fireSound = fireSound; </pre>
<pre><span> 10:</span> }</pre>
</div>
</div>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Once the sound effects are associated with the tank instance we start the engine sound after setting it to looping.
</p>
<p>The next step is to change the Update method of the Tank class to add updating the 3D buffer with the position of the tank. Add the following code to the end of the Update method:</p>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">if</span> (_engineSound != <span class="kwrd">null</span>)

  <br>{

  <br>_engineSound.Update(<span class="kwrd">base</span>.Position);

  <br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The shooting sound of the tank is not continuous, and whether or not the tank shoots will be determined by the AI we are going to add later on. For now, all we are going to do is create the necessary framework to play the shooting sound. Add the following
 method to the Tank class:</p>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> Shoot()

  <br>{

  <br><span class="kwrd">if</span> (_fireSound != <span class="kwrd">null</span>)

  <br>{

  <br>_fireSound.Update(<span class="kwrd">base</span>.Position);

  <br>_fireSound.Play();

  <br>}

  <br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The final step for updating the tank class to be sound ready is to update the CreateTanks method of the GameEngine. We need to create the SoundEffect for the engine noise and the firing noise, and pass them to the tank class on creation. Change the CreateTanks
 method to look as follows:</p>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> CreateTanks()

  <br>{

  <br>_tanks = <span class="kwrd">new</span> List&lt;UnitBase&gt;();

  <br>SoundEffects engineSound1 = <span class="kwrd">new</span> SoundEffects(_soundDevice, <span class="str">@&quot;EngineSound1.wav&quot;</span>);

  <br>engineSound1.Volume = -1000;

  <br>engineSound1.Frequency = 100000; <span class="rem">// Set to a value between 100 - 200000</span> SoundEffects engineSound2 = <span class="kwrd">new</span> SoundEffects(_soundDevice, <span class="str">@&quot;EngineSound2.wav&quot;</span>);

  <br>engineSound2.Volume = -1000;

  <br>engineSound2.Frequency = 10000; <span class="rem">// Set to a value between 100 - 200000</span> SoundEffects fireSound = <span class="kwrd">new</span> SoundEffects(_soundDevice, <span class="str">@&quot;Fire.wav&quot;</span>);

  <br>Tank newTank1 = <span class="kwrd">new</span> Tank(_device, <span class="str">@&quot;bigship1.x&quot;</span>, <span class="kwrd">new</span> Vector3(0.0f, 20.0f, 100.0f), 

  <br> 1f, 10.0f, fireSound, engineSound1);

  <br>Tank newTank2 = <span class="kwrd">new</span> Tank(_device, <span class="str">@&quot;bigship1.x&quot;</span>, <span class="kwrd">new</span> Vector3(100.0f, 20.0f, 100.0f), 

  <br> 1f, 10.0f, fireSound, engineSound2);

  <br>_tanks.Add(newTank1);

  <br>_tanks.Add(newTank2);

  <br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This is where you can experiment with changing the volume or frequency of the sound effect. Fly around and get closer to each spaceship, and the sound will vary in direction and volume according to your position. Change the frequency, and the pitch will
 change, and you can guess what the volume setting does.</p>
<h2>Summary</h2>
<p>When you play BattleTank2005 now, you should hear the engine noises of the various enemy tanks properly adjusted for their spatial relationship to the listener (you). At this point, we have integrated the first set of the audio features we want to add to
 BattleTank2005. You should definitely experiment with the various settings to hear their effect. I have left several optional settings commented in the code so you can easily change them. In the next article we are going to cover how to use the built-in sound
 effect manipulation of DirectSound to change the sounds, and how to play a regular MP3 file for the soundtrack using the AudioVideoPlayback namespace.</p>
<p>Until then: Happy coding!</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:bc4c75df1e224a01933a9e7600d92fd5">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VIII-DirectSound</comments>
      <itunes:summary>



&amp;nbsp;
In this article, we are going to look at another facet of DirectX, the ability to control sound devices.



Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware: 
Download: 


C# Download
VB Download

Beginning Game Development Series


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III








Welcome to the eighth article on beginning game development. We have spent a lot of time working with the graphics capabilities of DirectX. We also covered how the DirectX API allows us to control input devices. Now we are going to look at another facet
 of DirectX, the ability to control sound devices. This capability is found in the DirectSound and AudioVideoPlayback namespaces. 
Sound in Games 
Sound creates an ambiance in a game that provides for a more immersive game experience. Imagine how dull a game would be without sound effects; nothing would indicate when you fire your cannon or an explosion occurs. Sounds also can be used to increase the
 drama of a scene by increasing the tempo as the action increases.  
Sound effects also provide the same audible cues we expect in real life, such as the direction and speed of a person approaching us based on the volume, direction, and frequency of the footsteps. These sound effects add realism to the game just like proper
 physical behavior of objects do (something I will cover in an upcoming article a</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VIII-DirectSound</link>
      <pubDate>Mon, 06 Nov 2006 11:26:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VIII-DirectSound</guid>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>22</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-VIII-DirectSound/RSS</wfw:commentRss>
      <category>Gaming</category>
      <category>arcade</category>
    </item>
  <item>
      <title>Beginning Game Development: Part V - Adding Units</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This is Part 5 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers adding of 3D objects to the game using predefined mesh files and implementing
 some simple culling.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/windows/directx/default.mspx">DirectX SDK</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">None</span></div>
<div class="entry_details"><b>Download: </b>
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/941679/BattleTank2005Units-CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/941679/BattleTank2005Units-VB.msi">VB Download</a></li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<div class="entry_details"><strong>Beginning Game Development Series</strong></div>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
<p>Welcome to the fifth article on beginning game development. At this point we have a working 3D environment and can manipulate the camera direction and location using the keyboard and mouse. In this article we are going to add 3D objects to the game using
 predefined mesh files and implement some simple culling.</p>
<h4>Code cleanup</h4>
<p>The cleanup in this article consists mainly of fixing the navigation keys and removing some items we no longer need. The following changes have already been integrated into the code for this article:
</p>
<ul>
<li>Replaced the radian/degree conversion methods in the <b>Camera</b> class with the utility classes in the
<b>Geometry</b> class. </li><li>Fixed the key assignments in the <b>CheckForInput</b> method in the <b>GameEngine</b> class so that:
<ul>
<li>W and S adjust the Z-axis. W is forward (positive) and S backward (negative) </li><li>A and D adjust the X-axis. A is left (negative) and D is right (positive). </li><li>Q and Z adjust the Y-axis. Q is up (positive) and Z is down (negative). Movement along the Y-axis is going to be removed later on, since our tank can not fly.
</li></ul>
</li><li>Adjusted the initial position of the camera to be above the surface level by setting the
<code>_z</code> variable in the Camera class to 10. This represents our vantage point in the tank, which should be higher than zero.
</li><li>Removed the Joystick class. </li><li>Updated to the August SDK. </li><li>Changed the <b>GetElapsedTime</b> method in the <b>HiResTimer</b> class to return a float and changed
<code>_deltaTime</code> in <b>GameEngine</b> to a float. </li><li>Removed <b>HiResTimer.Reset</b> from the <b>GameEngine</b> <b>Render</b> method, moved
<b>HiResTimer.Start</b> into the constructor of the <b>GameEngine</b> class. </li></ul>
<h4>IDispose</h4>
<p>You may have noticed that some of the classes, such as the <b>Keyboard</b> and
<b>Mouse</b> classes, implement the <b>IDisposable</b> interface. This is an implementation of the Dispose pattern in .NET as explained in the .NET Framework Reference topic
<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconFinalizeDispose.asp">
Implementing Finalize and Dispose to Clean Up Unmanaged Resources.</a></p>
<p>The Dispose pattern in .NET is intended to be used when a program makes use of resources that are not managed by the .NET runtime. These &quot;unmanaged&quot; resources need to be cleaned up in a special way to ensure that they are released in a deterministic manner.
 Since the .NET garbage collection is non-deterministic, we need to use a particular set of steps to ensure this cleanup is done correctly. These steps are defined in the Dispose pattern.</p>
<p>We use a lot of unmanaged resources in game development, so it is best to implement the Dispose pattern in every class that interacts with DirectX or file resources (almost all of our classes). This will protect us against memory leaks and increase the performance
 of the game. </p>
<p>You can read the topic mentioned above to get more background information on this pattern and garbage collection for .NET. I have added the Dispose pattern in all of the classes for this article, and will do so going forward.
</p>
<p>What we need in BattleTank 2005 now are units. If you go back to the screenshot of the original game shown in the
<a href="http://blogs.msdn.com/coding4fun/gamedevelopment/beginning/default.aspx">
first article</a>, you see that we need to add shapes and opposing tanks. The shapes are obstacles for you or the enemy tanks to use as cover. The enemy tanks are what we are going to eventually shoot at. These objects also aid us in navigation in the otherwise
 bare landscape. You may remember that we had to write out the camera location to the console to see that we were moving because there were no reference points in the scene. In the next article we will complete the scene by adding some terrain.
</p>
<h4>Units</h4>
<p>For BattleTank 2005 we are going to have two types of 3D objects: Obstacles and Tanks. The main difference between them is that tanks can move and obstacles can not. Since we are going to have lots of obstacles and tanks, we are going to organize them so
 that they can be manipulated in bulk. We do this by adding them to a collection.
</p>
<p>We could add both types of objects to a single collection, but it makes sense to separate each type into its own collection. Separating the objects in this manner allows us to concentrate on a particular group without incurring the overhead of testing each
 unit for its type, which improves performance. We can then update the position of the mobile units while skipping the stationary units.
</p>
<h4>Generics</h4>
<p>In previous versions of .NET, creating a collection class to hold the units and ensuring that it was type-safe was pretty involved. Each collection in .NET 1.0 and 1.1 was a collection of objects. This meant that it accepted any value or reference type,
 making it very flexible. But this also meant that we had to cast the object to its proper type whenever we retrieved an object from the collection. This meant we ran the danger of the object cast failing. Accounting for the possible exception and testing each
 object before the cast incurred more overhead. </p>
<p>With .NET 2.0 we can use Generics to create type-safe collections for us with minimum effort. These collection classes are safer and perform better than regular collection. This is only one of the possible uses of generics, but probably the most common.
</p>
<p>To learn more about generics check out these articles at MSDN: </p>
<ul>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/csharp_generics.asp">An Introduction to C# Generics</a>
</li><li><a href="http://msdn.microsoft.com/msdnmag/issues/03/09/NET/">MSDN Magazine: Introducing Generics in the CLR</a></li></ul>
<p>All units, regardless of their purpose, have a number of things in common. To make the application easier to maintain, we are going to factor all of the common characteristics of the unit into a single base class. All units will derive from the common base
 class and be extended with custom properties and methods. </p>
<p>Creating a base class and derived classes creates an object hierarchy that then allows us to treat all units polymorphically, which is a very powerful concept in object oriented programming. Check out these Visual Studio .NET topics on polymorphism at MSDN:
</p>
<ul>
<li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcn7/html/vbconinheritancepolymorphismallthat.asp">Visual Basic Reference: Polymorphism</a>
</li><li><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbconImplementingInterfacesInComponents.asp">Visual Basic and Visual C# Concepts: Polymorphism in Components</a></li></ul>
<p>The resulting base class looks like this. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> UnitBase : IDisposable<br>{<br>    <span class="kwrd">public</span> UnitBase (Device device, <span class="kwrd">string</span> meshFile,<br>        Vector3 position, <span class="kwrd">float</span> scale )<br>    <span class="kwrd">public</span> <span class="kwrd">void</span> Render ( Camera camera )<br><br>    <span class="kwrd">public</span> <span class="kwrd">bool</span> IsCulled<br>    <span class="kwrd">public</span> Vector3 Position<br>    <span class="kwrd">public</span> <span class="kwrd">float</span> Radius<br>    <span class="kwrd">private</span> <span class="kwrd">void</span> LoadMesh ( )<br>    <span class="kwrd">private</span> <span class="kwrd">void</span> ComputeRadius ( )<br><br>    <span class="kwrd">private</span> Vector3 _position;<br>    <span class="kwrd">private</span> <span class="kwrd">float</span> _radius;<br>    <span class="kwrd">private</span> <span class="kwrd">bool</span> _isCulled;<br>    <span class="kwrd">private</span> Device _device;<br>    <span class="kwrd">private</span> <span class="kwrd">string</span> _meshFile;<br>    <span class="kwrd">private</span> <span class="kwrd">float</span> _scale;<br>    <span class="kwrd">private</span> Mesh _mesh = <span class="kwrd">null</span>;<br>    <span class="kwrd">private</span> Material[] _meshMaterials;<br>    <span class="kwrd">private</span> Texture[] _meshTextures;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">MustInherit</span> <span class="kwrd">Class</span> UnitBase<br>    <span class="kwrd">Implements</span> IDisposable<br>    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> device <span class="kwrd">As</span> Device, _<br>        <span class="kwrd">ByVal</span> meshFile <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> position <span class="kwrd">As</span> Vector3, _<br>        <span class="kwrd">ByVal</span> scale <span class="kwrd">As</span> <span class="kwrd">Single</span>)<br><br>    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> Render(<span class="kwrd">ByVal</span> camera <span class="kwrd">As</span> Camera)<br><br>    <span class="kwrd">Public</span> <span class="kwrd">Property</span> IsCulled() <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Position() <span class="kwrd">As</span> Vector3<br>    <span class="kwrd">Public</span> <span class="kwrd">Property</span> X() <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Y() <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Public</span> <span class="kwrd">Property</span> Z() <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Public</span> <span class="kwrd">ReadOnly</span> <span class="kwrd">Property</span> Radius() <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> Dispose() <span class="kwrd">Implements</span> IDisposable.Dispose<br>    <span class="kwrd">Protected</span> <span class="kwrd">Overridable</span> <span class="kwrd">Sub</span> Dispose(<span class="kwrd">ByVal</span> disposing <span class="kwrd">As</span> <span class="kwrd">Boolean</span>)<br>    <span class="kwrd">Protected</span> <span class="kwrd">Overrides</span> <span class="kwrd">Sub</span> Finalize()<br>    <span class="kwrd">Private</span> _disposed <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">Private</span> <span class="kwrd">Sub</span> LoadMesh()<br>    <span class="kwrd">Private</span> <span class="kwrd">Sub</span> ComputeRadius()<br>    <span class="kwrd">Private</span> m_position <span class="kwrd">As</span> Vector3<br>    <span class="kwrd">Private</span> m_radius <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Private</span> m_isCulled <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">Private</span> m_device <span class="kwrd">As</span> Device<br>    <span class="kwrd">Private</span> m_meshFile <span class="kwrd">As</span> <span class="kwrd">String</span>
    <span class="kwrd">Private</span> m_scale <span class="kwrd">As</span> <span class="kwrd">Single</span>
    <span class="kwrd">Private</span> m_mesh <span class="kwrd">As</span> Mesh = <span class="kwrd">Nothing</span>
    <span class="kwrd">Private</span> m_meshMaterials <span class="kwrd">As</span> Material()<br>    <span class="kwrd">Private</span> m_meshTextures <span class="kwrd">As</span> Texture()<br><span class="kwrd">End</span> Class</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>While most of this should make sense, you may be wondering what a mesh file is and why we are loading it.
</p>
<h4>3D Modeling</h4>
<p>At some point you realize that creating complex 3D objects in code line by line is pretty silly. The simple cube we created for the skybox alone was almost 200 lines of code. There has to be a better way to create 3D objects.
</p>
<p>Most 3D models are created by artists using dedicated modeling programs such as Maya or 3ds Max. These programs store the information about their models in proprietary file formats (iff for Maya and 3ds for 3DS Max). DirectX can not directly read these file
 formats, but it can read a format called the X file. </p>
<h4>X Files</h4>
<p>DirectX defines a file format called the X file format. It contains the definition for a 3D model. We can use these files to dramatically reduce the amount of code we need to write when loading 3D models into our game by loading them from the X file. In
 DirectX lingo, the X files are mesh files. </p>
<h4>Mesh</h4>
<p>If you remember from our previous article, a mesh is data that describes a 3D shape. Mesh data includes a list of vertices that comprise the shape, information on how the vertices are connected to each other, and texture information for all vertices.
</p>
<p>There are also conversion programs available that convert 3D objects files from other formats into the X file format. The DirectX SDK actually ships with plug-ins for Maya and 3ds Max that allow you to convert files created with these programs into the X
 file format. </p>
<p>So where can you get some X files to start working with? The DirectX SDK includes a folder called Media under the Samples folder which contains a number of X files that you can use. The DirectX SDK also includes a number of utilities that allow you to work
 with the X files such as the DirectX viewer and MeshViewer. All of the utilities are located in the Utilities folder. Check out these and the other utilities that come with the SDK, as they can save you time and effort.
</p>
<p><b>Free 3D models</b>: Unless you are very graphically talented it is probably best for an artist to create the models for your game. There are a large number of free 3D models available on the internet created by artists to show of their skills. Generally
 they don't mind if you use their work for you own gratification, but if you use it in a commercial game, that's a whole other issue. Make sure to read and understand the usage rules for each model before using it. A good site for free models is:
<a href="http://www.3dcafe.com/">http://www.3dcafe.com/</a>. </p>
<p>Using X files with predefined models opens up an entirely new world of integrating 3D objects into our game. No longer do we need to worry abut the low-level details of each object, we can simply load a previously created mesh file.
</p>
<h4>Updating the Skybox</h4>
<p>The first place we are going to use this newfound knowledge is to clean up the skybox code. The SDK includes a file called lobby_skybox.x in the Samples\Media\Lobby folder that describes a cube like the one we are currently using for our sky box. I copied
 this file to the Resources folder as skybox.x and updated the texture files to match the names of our texture files.
</p>
<p><b>Changing textures</b>: Most X files can be opened in a simple text editor. You can search the file for the references to the texture files (look for
<b>TextureFilename</b>) and replace them with your own, or you can substitute your own texture files during the mesh loading phase by passing the texture file name to the
<b>TextureLoader.FromFile</b> method. If you want to see something cool, copy the lobby_skybox.x files and all of the JPG files from the SDK media folder to the resource folder, then change the name of the X file in the skybox LoadMesh method to this X file.
 The resulting skybox is the lobby of the building where all the game developers work at Microsoft.
</p>
<p>In the Skybox class remove the <b>SetupCubeFaces</b> method, the six methods starting with Copy (<b>CopyLeftFaceVertexBuffer</b>,
<b>CopyFrontFaceVertexBuffer</b>, etc.) and the <b>RenderFace</b> method. You can also remove all of the private variables declared at the bottom of the class except for the Device variable. In the
<b>Render</b> method, remove the lines of code that check the Pitch and Heading of the camera. Finally, replace the call to
<b>SetupCubeFaces</b> in the constructor with a call to <b>LoadMesh</b>. </p>
<p>Now add the following three variable declarations at the bottom of the class. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> Mesh _mesh = <span class="kwrd">null</span>;<br><span class="kwrd">private</span> Material[] _meshMaterials;<br><span class="kwrd">private</span> Texture[] _meshTextures;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> m_mesh <span class="kwrd">As</span> Mesh = <span class="kwrd">Nothing</span>
<span class="kwrd">Private</span> m_meshMaterials <span class="kwrd">As</span> Material()<br><span class="kwrd">Private</span> m_meshTextures <span class="kwrd">As</span> Texture()</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>We already know what a mesh and a texture is, but what is the material? </p>
<h4>Material</h4>
<p>Materials describe how polygons reflect ambient and diffuse light, as well as information about specular highlights and if the polygons appear to emit light. The main thing to remember is that while textures define how polygons look, materials define how
 they reflect light. </p>
<h4>Loading a Mesh</h4>
<p>Loading the mesh from a file is very simple. All you have to do is to call the
<b>FromFile</b> method of the <b>Mesh</b> class. (You should spend some time to familiarize yourself with the Mesh class and its methods, since it is one of the core classes you will use.)
</p>
<p>In the Skybox class add the following code. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> LoadMesh ( )<br>{<br>    ExtendedMaterial[] materials = <span class="kwrd">null</span>;<br>    Directory.SetCurrentDirectory ( <br>        Application.StartupPath &#43; <span class="str">@&quot;\..\..\..\Resources\&quot; );<br>    _mesh = Mesh.FromFile (@&quot;</span>skybox.x&quot;,<br>        MeshFlags.SystemMemory, _device, <span class="kwrd">out</span> materials);<br>    <span class="kwrd">if</span> ( ( materials != <span class="kwrd">null</span> ) &amp;&amp; ( materials.Length &gt; 0 ) )<br>    {<br>        _meshTextures = <span class="kwrd">new</span> Texture[materials.Length];<br>        _meshMaterials = <span class="kwrd">new</span> Material[materials.Length];<br>        <span class="kwrd">for</span> ( <span class="kwrd">int</span> i = 0 ; i &lt; materials.Length ; i&#43;&#43; )<br>        {<br>            _meshMaterials[i] = materials[i].Material3D;<br>            _meshMaterials[i].Ambient = _meshMaterials[i].Diffuse;<br>            <span class="kwrd">if</span> (materials[i].TextureFilename != <span class="kwrd">null</span> &amp;&amp; <br>                    (materials[i].TextureFilename != <span class="kwrd">string</span>.Empty))<br>                _meshTextures[i] = TextureLoader.FromFile ( _device, <br>                    materials[i].TextureFilename );<br>        }<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> LoadMesh()<br>    <span class="kwrd">Dim</span> materials <span class="kwrd">As</span> ExtendedMaterial() = <span class="kwrd">Nothing</span>
    Directory.SetCurrentDirectory(Application.StartupPath _ 
        &amp; <span class="str">&quot;\..\..\..\Resources\&quot;</span>)<br>    m_mesh = Mesh.FromFile(<span class="str">&quot;skybox.x&quot;</span>, MeshFlags.SystemMemory, _<br>        m_device, materials)<br><br>    <span class="kwrd">If</span> (<span class="kwrd">Not</span> (materials <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>)) <span class="kwrd">AndAlso</span> _<br>        (materials.Length &gt; 0) <span class="kwrd">Then</span>
        m_meshTextures = <span class="kwrd">New</span> Texture(materials.Length) {}<br>        m_meshMaterials = <span class="kwrd">New</span> Material(materials.Length) {}<br>        <span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0<br>        <span class="kwrd">While</span> i &lt; materials.Length<br>            m_meshMaterials(i) = materials(i).Material3D<br>            m_meshMaterials(i).Ambient = m_meshMaterials(i).Diffuse<br>            <span class="kwrd">If</span> <span class="kwrd">Not</span> (materials(i).TextureFilename <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">AndAlso</span> _<br>                    (<span class="kwrd">Not</span> (materials(i).TextureFilename = <span class="kwrd">String</span>.Empty)) <span class="kwrd">Then</span>
                m_meshTextures(i) = TextureLoader.FromFile( _
                    m_device, materials(i).TextureFilename)
            <span class="kwrd">End</span> <span class="kwrd">If</span>
            System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
        <span class="kwrd">End</span> <span class="kwrd">While</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>While DirectX handles most of the work of reading the X file and converting it into an object for us (i.e. the creation of the vertex and index buffers etc.) we have to manually manage loading the materials and textures for the mesh.
</p>
<p>The last step to integrate the X file and textures into the Skybox is to modify the
<b>Render</b> method of the <b>Skybox</b> class. Immediately after the <code>_device.RenderState.CullMode = Microsoft.DirectX.Direct3D.Cull.None;</code> line add the following code.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">for</span> ( <span class="kwrd">int</span> i = 0 ; i &lt; _meshMaterials.Length ; i&#43;&#43; )<br>{<br>    _device.Material = _meshMaterials[i];<br>    _device.SetTexture ( 0, _meshTextures[i] );<br>    _mesh.DrawSubset ( i );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">While</span> i &lt; m_meshMaterials.Length<br>    m_device.Material = m_meshMaterials(i)<br>    m_device.SetTexture(0, m_meshTextures(i))<br>    m_mesh.DrawSubset(i)<br>    System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)<br><span class="kwrd">End</span> While</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Once again we iterate over the <b>meshMaterials</b> and then call the <b>DrawSubset</b> method of the
<b>Mesh</b> to draw each subset in turn. That's it; the entire <b>Skybox</b> class is now only about 80 lines long and much easier to read.
</p>
<p>Returning to the <b>UnitBase</b> class, the next item we need to look at is the
<b>IsCulled</b> flag. </p>
<h4>Culling</h4>
<p>We briefly covered culling in the third article. Culling is simply the removal of entire objects from the scene so they will not be rendered. The logic to determine what objects should be removed can range from the very simple to the very complex. In BattleTank
 2005 we are going to cull all of the objects that do not fall into the view frustum of the scene.
</p>
<p>To determine if the unit is in the view frustum, we enhance the <b>Camera</b> class to provide us the info about the current view frustum so that we can check each object and see if it falls inside or outside of the frustum. To perform this check, we use
 the <b>Radius</b> property of the <b>UnitBase</b> class which is computed in the ComputeRadius method.
</p>
<p>The <b>BoundingSphere</b> method of the <b>Geometry</b> class (the same one we use now for converting radians to degrees and vice versa) computes a sphere that completely contains all the points in the mesh using a vertex data of the mesh. The mesh contains
 this information in the vertex buffer. To access this buffer, it is best to lock it before access and unlock it when done. You should also make sure to dispose the vertex buffer when you are done. The safest way to do this is to leverage the
<code>using</code> statement that will ensure that <b>Dispose</b> is called regardless of what happens.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> ComputeRadius ( )<br>{<br>    <span class="kwrd">using</span> ( VertexBuffer vertexBuffer = _mesh.VertexBuffer )<br>    {<br>        GraphicsStream gStream = vertexBuffer.Lock ( 0, 0,<br>            LockFlags.None );<br>        Vector3 tempCenter;<br><br>        _radius = Geometry.ComputeBoundingSphere (gStream,<br>            _mesh.NumberVertices, _mesh.VertexFormat, <br>            <span class="kwrd">out</span> tempCenter ) * _scale;<br><br>        vertexBuffer.Unlock ( );<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> ComputeRadius()<br>    <span class="kwrd">Dim</span> vertexBuffer <span class="kwrd">As</span> VertexBuffer = <span class="kwrd">Nothing</span>
    <span class="kwrd">Try</span>
        vertexBuffer = m_mesh.VertexBuffer
        <span class="kwrd">Dim</span> gStream <span class="kwrd">As</span> GraphicsStream = _<br>            vertexBuffer.Lock(0, 0, LockFlags.None)<br>        <span class="kwrd">Dim</span> tempCenter <span class="kwrd">As</span> Vector3<br>        m_radius = Geometry.ComputeBoundingSphere(gStream, _<br>            m_mesh.NumberVertices, m_mesh.VertexFormat, tempCenter) * _<br>            m_scale<br>    <span class="kwrd">Finally</span>
        vertexBuffer.Unlock()
        vertexBuffer.Dispose()
    <span class="kwrd">End</span> <span class="kwrd">Try</span>
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>You can probably understand why using the radius of the object is a very rough way of culling objects. It works fine and is fairly accurate if the objects are simple shapes, but for more complex shapes the bounding sphere becomes much larger than the basic
 object itself. </p>
<p>In a commercial game a lot of effort is invested in creating a culling routine that eliminates the most objects it can. We could also get fancy here and identify objects that are only partially in the frustum, but without the corresponding ability to render
 only a portion of the unit, we are just wasting our time. Instead we will treat any unit that has even a single point in the view frustum as being completely in the frustum.
</p>
<p>So now that we have the radius of the unit, we need to know what the frustum is so we can check the radius against it.
</p>
<h4>View Frustum</h4>
<p>Adding the frustum info to the camera is easy. First we add some data structures to hold the information about the view frustum. If you recall from the previous article, a frustum resembles a pyramid with the top cut off. This means that we need to store
 the corners of the top and bottom square and the plane for each side. For the corners we use an array of the familiar
<b>Vector3</b> structure. For the planes DirectX provides a convenient <b>Plane</b> structure.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> Vector3[] _frustumCorners;<br><span class="kwrd">private</span> Plane[] _frustumPlanes;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> Vector3[] _frustumCorners;<br><span class="kwrd">private</span> Plane[] _frustumPlanes;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>We then initialize the arrays in the constructor (two squares with four corners equals 8 points, and the four sides of the polygon plus the top and bottom make six planes).
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_frustumCorners = <span class="kwrd">new</span> Vector3[8];<br>_frustumPlanes = <span class="kwrd">new</span> Plane[6];</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">m_frustumCorners = New Vector3(8) {}<br>m_frustumPlanes = New Plane(6) {}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The next step is to compute the frustum using the current view and projection matrices.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> ComputeViewFrustum ( )<br>{<br>    Matrix matrix = _viewMatrix * _perspectiveMatrix;<br>    matrix.Invert ( );<br><br>    _frustumCorners[0] = <span class="kwrd">new</span> Vector3 ( -1.0f, -1.0f, 0.0f ); <span class="rem">// xyz</span>
    _frustumCorners[1] = <span class="kwrd">new</span> Vector3 ( 1.0f, -1.0f, 0.0f ); <span class="rem">// Xyz</span>
    _frustumCorners[2] = <span class="kwrd">new</span> Vector3 ( -1.0f, 1.0f, 0.0f ); <span class="rem">// xYz</span>
    _frustumCorners[3] = <span class="kwrd">new</span> Vector3 ( 1.0f, 1.0f, 0.0f ); <span class="rem">// XYz</span>
    _frustumCorners[4] = <span class="kwrd">new</span> Vector3 ( -1.0f, -1.0f, 1.0f ); <span class="rem">// xyZ</span>
    _frustumCorners[5] = <span class="kwrd">new</span> Vector3 ( 1.0f, -1.0f, 1.0f ); <span class="rem">// XyZ</span>
    _frustumCorners[6] = <span class="kwrd">new</span> Vector3 ( -1.0f, 1.0f, 1.0f ); <span class="rem">// xYZ</span>
    _frustumCorners[7] = <span class="kwrd">new</span> Vector3 ( 1.0f, 1.0f, 1.0f ); <span class="rem">// XYZ</span>
    <span class="kwrd">for</span> ( <span class="kwrd">int</span> i = 0 ; i &lt; _frustumCorners.Length ; i&#43;&#43; )<br>        _frustumCorners[i] = Vector3.TransformCoordinate (<br>            _frustumCorners[i], matrix );<br><br>    <span class="rem">// Now calculate the planes</span>
    _frustumPlanes[0] = Plane.FromPoints (
        _frustumCorners[0], 
        _frustumCorners[1], 
        _frustumCorners[2] ); <span class="rem">// Near</span>
    _frustumPlanes[1] = Plane.FromPoints ( 
        _frustumCorners[6], 
        _frustumCorners[7], 
        _frustumCorners[5] ); <span class="rem">// Far</span>
    _frustumPlanes[2] = Plane.FromPoints ( 
        _frustumCorners[2], 
        _frustumCorners[6], 
        _frustumCorners[4] ); <span class="rem">// Left</span>
    _frustumPlanes[3] = Plane.FromPoints ( 
        _frustumCorners[7], 
        _frustumCorners[3], 
        _frustumCorners[5] ); <span class="rem">// Right</span>
    _frustumPlanes[4] = Plane.FromPoints ( 
        _frustumCorners[2], 
        _frustumCorners[3], 
        _frustumCorners[6] ); <span class="rem">// Top</span>
    _frustumPlanes[5] = Plane.FromPoints ( 
        _frustumCorners[1], 
        _frustumCorners[0], 
        _frustumCorners[4] ); <span class="rem">// Bottom</span>
}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> ComputeViewFrustum()<br>    <span class="kwrd">Dim</span> matrix <span class="kwrd">As</span> Matrix = m_viewMatrix * m_perspectiveMatrix<br>    matrix.Invert()<br>    m_frustumCorners(0) = <span class="kwrd">New</span> Vector3(-1.0F, -1.0F, 0.0F)<br>    m_frustumCorners(1) = <span class="kwrd">New</span> Vector3(1.0F, -1.0F, 0.0F)<br>    m_frustumCorners(2) = <span class="kwrd">New</span> Vector3(-1.0F, 1.0F, 0.0F)<br>    m_frustumCorners(3) = <span class="kwrd">New</span> Vector3(1.0F, 1.0F, 0.0F)<br>    m_frustumCorners(4) = <span class="kwrd">New</span> Vector3(-1.0F, -1.0F, 1.0F)<br>    m_frustumCorners(5) = <span class="kwrd">New</span> Vector3(1.0F, -1.0F, 1.0F)<br>    m_frustumCorners(6) = <span class="kwrd">New</span> Vector3(-1.0F, 1.0F, 1.0F)<br>    m_frustumCorners(7) = <span class="kwrd">New</span> Vector3(1.0F, 1.0F, 1.0F)<br>    <span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0<br>    <span class="kwrd">While</span> i &lt; m_frustumCorners.Length<br>        m_frustumCorners(i) = _<br>            Vector3.TransformCoordinate(m_frustumCorners(i), matrix)<br>        System.Math.Min( _<br>            System.Threading.Interlocked.Increment(i), i - 1)<br>    <span class="kwrd">End</span> <span class="kwrd">While</span>
    m_frustumPlanes(0) = Plane.FromPoints(m_frustumCorners(0), 
        m_frustumCorners(1), m_frustumCorners(2))
    m_frustumPlanes(1) = Plane.FromPoints( _
        m_frustumCorners(6), _
        m_frustumCorners(7), _
        m_frustumCorners(5))
    m_frustumPlanes(2) = Plane.FromPoints( _
        m_frustumCorners(2), _
        m_frustumCorners(6), _
        m_frustumCorners(4))
    m_frustumPlanes(3) = Plane.FromPoints( _
        m_frustumCorners(7), _
        m_frustumCorners(3), _
        m_frustumCorners(5))
    m_frustumPlanes(4) = Plane.FromPoints( _
        m_frustumCorners(2), _
        m_frustumCorners(3), _
        m_frustumCorners(6))
    m_frustumPlanes(5) = Plane.FromPoints( _
        m_frustumCorners(1), _
        m_frustumCorners(0), _
        m_frustumCorners(4))
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>First we combine the view and projection matrices by multiplying them. Next we initialize the eight corners of the frustum as a cube immediately in front of the camera. These corners are then transformed and used to create the 6 planes using the
<b>FromPoints</b> method of the plane. </p>
<p>The frustum is computed upon initialization of the class and on each render loop. Add a call to
<b>ComputeViewFrustum( )</b> to the bottom of the constructor of the <b>Camera</b> class and at the end of the
<b>Render</b> method of the <b>Camera</b> class. (It needs to be at the end so it can use the newly computed view and projection matrices.) Now we can use the computed frustum and the radius for each unit to determine whether any part of the unit is in the
 frustum and should be rendered. The <b>IsInViewFrustum</b> method returns true if the unit is inside the frustum and false otherwise.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">bool</span> IsInViewFrustum ( UnitBase unitToCheck )<br>{<br>    <span class="kwrd">foreach</span> ( Plane plane <span class="kwrd">in</span> _frustumPlanes )<br>    {<br>        <span class="kwrd">if</span> ( plane.A * unitToCheck.Position.X &#43; plane.B *<br>             unitToCheck.Position.Y &#43; plane.C * unitToCheck.Position.Z &#43; <br>             plane.D &lt;= ( -unitToCheck.Radius ) )<br>        <span class="kwrd">return</span> <span class="kwrd">false</span>;<br>    }<br>    <span class="kwrd">return</span> <span class="kwrd">true</span>;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Function</span> IsInViewFrustum(<span class="kwrd">ByVal</span> unitToCheck <span class="kwrd">As</span> UnitBase) <span class="kwrd">As</span> <span class="kwrd">Boolean</span>
    <span class="kwrd">For</span> <span class="kwrd">Each</span> plane <span class="kwrd">As</span> Plane <span class="kwrd">In</span> m_frustumPlanes<br>        <span class="kwrd">If</span> plane.A * unitToCheck.Position.X &#43; plane.B * _<br>            unitToCheck.Position.Y &#43; plane.C * unitToCheck.Position.Z &#43; _<br>            plane.D &lt;= (-unitToCheck.Radius) <span class="kwrd">Then</span>
            <span class="kwrd">Return</span> <span class="kwrd">False</span>
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Next</span>
    <span class="kwrd">Return</span> <span class="kwrd">True</span>
<span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The process of culling should take place before the unit is rendered. We accomplish this in the
<b>Render</b> method of the <b>BaseUnit</b> class by checking the frustum of the camera before actually rendering the mesh. By placing it into the actual
<b>Render</b> method, we avoid having to check the cull state elsewhere in the code.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> (camera.IsInViewFrustum ( <span class="kwrd">this</span> ) == <span class="kwrd">false</span> )<br>    <span class="kwrd">return</span>;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> camera.IsInViewFrustum(<span class="kwrd">Me</span>) = <span class="kwrd">False</span> <span class="kwrd">Then</span>
    <span class="kwrd">Return</span>
<span class="kwrd">End</span> If</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now that we have the basic infrastructure in place, it's time to start adding units. But the
<b>UnitBase</b> class is abstract, so it can not be instantiated. The entire purpose of the base class was to keep common unit properties and functionality together. Now it's time to create some classes that represent the objects we are going to use in BattleTank
 2005, namely obstacles and tanks. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Obstacle : UnitBase<br>{<br>    <span class="kwrd">public</span> Obstacle ( Device device, <span class="kwrd">string</span> meshFile, <br>        Vector3 position, <span class="kwrd">float</span> scale )<br>         : <span class="kwrd">base</span> ( device, meshFile, position, scale )<br>    {<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> Obstacle<br>    <span class="kwrd">Inherits</span> UnitBase<br><br>    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> device <span class="kwrd">As</span> Device, <span class="kwrd">ByVal</span> meshFile <span class="kwrd">As</span> <span class="kwrd">String</span>, _<br>    <span class="kwrd">ByVal</span> position <span class="kwrd">As</span> Vector3, <span class="kwrd">ByVal</span> scale <span class="kwrd">As</span> <span class="kwrd">Single</span>)<br>        <span class="kwrd">MyBase</span>.<span class="kwrd">New</span>(device, meshFile, position, scale)<br>    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
<span class="kwrd">End</span> Class</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>Obstacle</b> class currently does nothing more than call its base class, but we are going add to this class later on.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> Tank : UnitBase<br>{<br>    <span class="kwrd">public</span> Tank ( Device device, <span class="kwrd">string</span> meshFile, <br>        Vector3 position, <span class="kwrd">float</span> scale ) <br>        : <span class="kwrd">base</span> ( device, meshFile, position, scale )<br>    <span class="kwrd">public</span> <span class="kwrd">void</span> Update ( <span class="kwrd">float</span> deltaTime )<br>    <span class="kwrd">private</span> <span class="kwrd">float</span> _speed = 10.0f;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Class</span> Tank<br>    <span class="kwrd">Inherits</span> UnitBase<br><br>    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>(<span class="kwrd">ByVal</span> device <span class="kwrd">As</span> Device, <span class="kwrd">ByVal</span> meshFile <span class="kwrd">As</span> <span class="kwrd">String</span>, _<br>        <span class="kwrd">ByVal</span> position <span class="kwrd">As</span> Vector3, <span class="kwrd">ByVal</span> scale <span class="kwrd">As</span> <span class="kwrd">Single</span>)<br>        <span class="kwrd">MyBase</span>.<span class="kwrd">New</span>(device, meshFile, position, scale)<br>    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> Update(<span class="kwrd">ByVal</span> deltaTime <span class="kwrd">As</span> <span class="kwrd">Single</span>)<br>        <span class="kwrd">MyBase</span>.Z -= (m_speed * deltaTime)<br>    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
    <span class="kwrd">Private</span> m_speed <span class="kwrd">As</span> <span class="kwrd">Single</span> = 10.0F<br><span class="kwrd">End</span> Class</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>Tank</b> class adds a <code>_speed</code> property we need to describe and an
<b>Update</b> method. </p>
<h4>Using time to simulate movement</h4>
<p>The <b>Update</b> method takes in a float that describes the amount of time in seconds that has passed since the last render loop. In the second article we added a variable called
<b>deltaTime</b> which we used to compute the frame rate. This value is the value we want to use from now on to compute the position of moving objects. We use the principle of time to ensure a similar experience on each computer regardless of the speed of the
 computer and make the movement appear fluid. For example, if we updated the position of a moving object by 1 in each pass through the render loop, the object would move fast on faster computers since they are able to complete a render loop faster. You may
 have seen this behavior when experimenting with the rotating cube. Another problem is that each pass through the render loop is not performed at the same speed, depending on the other operations the CPU is performing, so that the movement may appear choppy.
 (Again, the easiest way to understand this is to experiment. Change the increment of the Z axis by one instead of the speed * time formula and see what happens.)
</p>
<p>Notice that we only need to update the tanks since the obstacles do not move. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">foreach</span> ( Tank tank <span class="kwrd">in</span> _tanks )<br>{<br>    tank.Update ( _deltaTime );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">For</span> <span class="kwrd">Each</span> tank <span class="kwrd">As</span> Tank <span class="kwrd">In</span> m_tanks<br>    tank.Update(m_deltaTime)<br>Next</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The actual <b>Update</b> method in the tank simply moves the tank towards the origin for now, using a predefined speed.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> Update ( <span class="kwrd">float</span> deltaTime )<br>{<br>    <span class="kwrd">base</span>.Z -= ( _speed * deltaTime );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> Update(<span class="kwrd">ByVal</span> deltaTime <span class="kwrd">As</span> <span class="kwrd">Single</span>)<br>    <span class="kwrd">MyBase</span>.Z -= (m_speed * deltaTime)<br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Next we create two generic collections in the <b>GameEngine</b> class to hold the mobile and stationery units.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> List&lt;UnitBase&gt; _obstacles;<br><span class="kwrd">private</span> List&lt;UnitBase&gt; _tanks;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> List&lt;UnitBase&gt; _obstacles;<br><span class="kwrd">private</span> List&lt;UnitBase&gt; _tanks;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The actual units are added to the collection in the <b>CreateObstacles</b> and
<b>CreateTanks</b> methods. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> CreateObstacles ( )<br>{<br>    _obstacles = <span class="kwrd">new</span> List&lt;UnitBase&gt; ( );<br>    _obstacles.Add ( <span class="kwrd">new</span> Obstacle ( _device, <span class="str">@&quot;car.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( 0, 0, 200 ), 1f ) );<br>    _obstacles.Add ( <span class="kwrd">new</span> Obstacle ( _device, <span class="str">@&quot;car.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( 60, 0, 100 ), 1f ) );<br>    _obstacles.Add ( <span class="kwrd">new</span> Obstacle ( _device, <span class="str">@&quot;car.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( -60, 0, 150 ), 1f ) );<br>    _obstacles.Add ( <span class="kwrd">new</span> Obstacle ( _device, <span class="str">@&quot;car.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( 60, 0, -100 ), 1f ) );<br>    _obstacles.Add ( <span class="kwrd">new</span> Obstacle ( _device, <span class="str">@&quot;car.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( -60, 0, -150 ), 1f ) );<br>}<br><br><span class="kwrd">private</span> <span class="kwrd">void</span> CreateTanks ( )<br>{<br>    _tanks = <span class="kwrd">new</span> List&lt;UnitBase&gt; ( );<br>    _tanks.Add ( <span class="kwrd">new</span> Tank (_device, <span class="str">@&quot;bigship1.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( 0, 0, 200 ), 1f ) );<br>    _tanks.Add ( <span class="kwrd">new</span> Tank (_device, <span class="str">@&quot;bigship1.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( 100, 0, 300 ), 1f ) );<br>    _tanks.Add ( <span class="kwrd">new</span> Tank (_device, <span class="str">@&quot;bigship1.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( -100, 0, 500 ), 1f ) );<br>    _tanks.Add ( <span class="kwrd">new</span> Tank (_device, <span class="str">@&quot;bigship1.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( 100, 0, -200 ), 1f ) );<br>    _tanks.Add ( <span class="kwrd">new</span> Tank (_device, <span class="str">@&quot;bigship1.x&quot;</span>, <br>        <span class="kwrd">new</span> Vector3 ( -100, 0, -400 ), 1f ) );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> CreateObstacles()<br>    m_obstacles = <span class="kwrd">New</span> List(Of UnitBase)()<br>    m_obstacles.Add(<span class="kwrd">New</span> Obstacle(m_device, <span class="str">&quot;car.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(0, 0, 200), 1.0F))<br>    m_obstacles.Add(<span class="kwrd">New</span> Obstacle(m_device, <span class="str">&quot;car.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(60, 0, 100), 1.0F))<br>    m_obstacles.Add(<span class="kwrd">New</span> Obstacle(m_device, <span class="str">&quot;car.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(-60, 0, 150), 1.0F))<br>    m_obstacles.Add(<span class="kwrd">New</span> Obstacle(m_device, <span class="str">&quot;car.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(60, 0, -100), 1.0F))<br>    m_obstacles.Add(<span class="kwrd">New</span> Obstacle(m_device, <span class="str">&quot;car.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(-60, 0, -150), 1.0F))<br><span class="kwrd">End</span> <span class="kwrd">Sub</span>
<span class="kwrd">Private</span> <span class="kwrd">Sub</span> CreateTanks()<br>    m_tanks = <span class="kwrd">New</span> List(Of UnitBase)<br>    m_tanks.Add(<span class="kwrd">New</span> Tank(m_device, <span class="str">&quot;bigship1.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(0, 0, 200),1.0F))<br>    m_tanks.Add(<span class="kwrd">New</span> Tank(m_device, <span class="str">&quot;bigship1.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(100, 0, 300), 1.0F))<br>    m_tanks.Add(<span class="kwrd">New</span> Tank(m_device, <span class="str">&quot;bigship1.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(-100, 0, 500), 1.0F))<br>    m_tanks.Add(<span class="kwrd">New</span> Tank(m_device, <span class="str">&quot;bigship1.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(100, 0, -200), 1.0F))<br>    m_tanks.Add(<span class="kwrd">New</span> Tank(m_device, <span class="str">&quot;bigship1.x&quot;</span>, _<br>        <span class="kwrd">New</span> Vector3(-100, 0, -400), 1.0F))<br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>If you look at the coordinates for the obstacles and tanks, you will see that I placed them along similar axes to help me orient myself. You could also modify these methods to create a random number of obstacles and tanks placed at random coordinates. Just
 make sure to add logic to avoid objects overlapping each other or being too close to the origin and obscuring the camera.
</p>
<h4>Levels</h4>
<p>A more flexible and extensible solution is to read the number, type and location of obstacles and tanks from a file. This file could also contain other play-specific settings and be loaded automatically based on some internal logic. The most common use of
 this scenario is for predefined levels. A player would have the ability to advance to more difficult levels after meeting some completion criteria. This allows you to easily create an ever-changing play experience and fine-tune the playability of each level,
 something you can't do with random placement. Setting the game up that way also allows players to customize the game for themselves. You would normally provide a level editor when following this route.
</p>
<p>The final step is to call these methods. The best place is the constructor of the
<b>GameEngine</b> class right after the <b>Camera</b> class is created. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> GameEngine ()<br>{<br>    InitializeComponent ( );<br>    <span class="kwrd">this</span>.SetStyle (ControlStyles.AllPaintingInWmPaint | <br>                    ControlStyles.Opaque, <span class="kwrd">true</span> );<br>    ConfigureInputDevices ( );<br>    ConfigureDevice ( );<br>    _skyBox = <span class="kwrd">new</span> SkyBox ( <span class="kwrd">this</span>._device );<br>    _camera = <span class="kwrd">new</span> Camera ( );<br>    CreateObstacles ( );<br>    CreateTanks ( );<br>    <span class="kwrd">this</span>.Size = <span class="kwrd">new</span> Size ( 800, 600 );<br>    HiResTimer.Start ( );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>()<br>    InitializeComponent()<br>    <span class="kwrd">Me</span>.SetStyle(ControlStyles.AllPaintingInWmPaint <span class="kwrd">Or</span> _<br>        ControlStyles.Opaque, <span class="kwrd">True</span>)<br>    ConfigureInputDevices()<br>    ConfigureDevice()<br>    m_skyBox = <span class="kwrd">New</span> SkyBox(<span class="kwrd">Me</span>.m_device)<br>    m_camera = <span class="kwrd">New</span> Camera<br>    CreateObstacles()<br>    CreateTanks()<br>    <span class="kwrd">Me</span>.Size = <span class="kwrd">New</span> Size(800, 600)<br>    HiResTimer.Start()<br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>On each render loop all we have to do is to iterate over the appropriate collection and render those that are in the frustum. We call the
<b>RenderUnits</b> method in the <b>Render</b> method of the <b>GameEngine</b> class immediately after rendering the skybox.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> RenderUnits ( )<br>{<br>    <span class="kwrd">foreach</span> ( UnitBase ub <span class="kwrd">in</span> _obstacles )<br>    {<br>        ub.Render ( _camera );<br>    }<br><br>    <span class="kwrd">foreach</span> ( UnitBase ub <span class="kwrd">in</span> _tanks )<br>   {<br>        ub.Render ( _camera );<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> RenderUnits()<br>    <span class="kwrd">For</span> <span class="kwrd">Each</span> ub <span class="kwrd">As</span> UnitBase <span class="kwrd">In</span> m_obstacles<br>        ub.Render(m_camera)<br>    <span class="kwrd">Next</span>
    <span class="kwrd">For</span> <span class="kwrd">Each</span> ub <span class="kwrd">As</span> UnitBase <span class="kwrd">In</span> m_tanks<br>        ub.Render(m_camera)<br>    <span class="kwrd">Next</span>
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>That's all. Now we have units. </p>
<h4>Conclusion</h4>
<p>If you run the game now you will notice three things. </p>
<ul>
<li>The units seem to float in mid-space. </li><li>The units are all white. </li><li>You can drive right through each unit. </li></ul>
<p>The first problem can be solved by adding a terrain to the game to show a solid surface along the Y axis. The second problem can be solved by adding lights to the scene. The final issue will be solved once we add collision detection to the game. Other then
 these items, the game is getting more playable by the day. In the next article we are going to add the missing terrain using a heightmap, add lights so we can see the colors of the units, and add some collision detection.
</p>
<p>As you may have noticed, I have changed (and will continue to do so) the various graphics in the game from article to article. This is intended to encourage you to implement your own graphics to change the underlying game into something completely different.
 You could easily change this game to be set in space, or turn it into a powerboat racing game by just changing the graphics. Give it a try.
</p>
<p>As usual, I ran out of time. In the last article I had promised to add the HUD back, but I ran out of space. I will try to accomplish this in the coming articles. I also wanted to discuss Action mapping to enhance the way we are tracking the keyboard and
 mouse inputs, but this subject will have to be covered in a later article. In addition, I am planning to add a simple debugging console to the game.
</p>
<p>Along with these features, the next articles are going to discuss adding Artificial Intelligence to the opposing tanks, making our game conform to realistic physical forces, and some cool sounds to make playing the game more fun. So stay tuned.
</p>
<p>Until then: Happy coding.</p>
<span>]]&gt;</span> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:c48ff79c952a49ecb51e9e7600d9606b">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-V-Adding-Units</comments>
      <itunes:summary>



&amp;nbsp;
This is Part 5 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers adding of 3D objects to the game using predefined mesh files and implementing
 some simple culling.



Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
3-6 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions,
DirectX SDK
Hardware: None
Download: 

C# Download
VB Download






Beginning Game Development Series


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III



Welcome to the fifth article on beginning game development. At this point we have a working 3D environment and can manipulate the camera direction and location using the keyboard and mouse. In this article we are going to add 3D objects to the game using
 predefined mesh files and implement some simple culling. 
Code cleanup
The cleanup in this article consists mainly of fixing the navigation keys and removing some items we no longer need. The following changes have already been integrated into the code for this article:
 

Replaced the radian/degree conversion methods in the Camera class with the utility classes in the
Geometry class. Fixed the key assignments in the CheckForInput method in the GameEngine class so that:

W and S adjust the Z-axis. W is forward (positive) and S backward (negative) A and D adjust the X-axis. A is left (negative) and D is right (positive). Q and Z adjust the Y-axis. Q </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-V-Adding-Units</link>
      <pubDate>Fri, 03 Nov 2006 08:03:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-V-Adding-Units</guid>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>7</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-V-Adding-Units/RSS</wfw:commentRss>
      <category>Gaming</category>
      <category>arcade</category>
    </item>
  <item>
      <title>Beginning Game Development: Part IV - DirectInput</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This is Part 4 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers the input device portion of DirectX, called DirectInput.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/windows/directx/default.mspx">DirectX SDK</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">None</span></div>
<div class="entry_details"><b>Download: </b>
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/940908/BattleTank2005CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/940908/BattleTank2005VB.msi">VB Download</a></li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<div class="entry_details"><strong>Beginning Game Development Series</strong></div>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
<p>Welcome to the fourth article on beginning game development. In this article we are going to cover the input device portion of DirectX, called DirectInput. Using DirectInput you can control joysticks, a mouse or the keyboard.
</p>
<p>Before we start I need to cover a couple of items that were brought to my attention via feedback from the readers (thank you everyone for taking the time to do this) and changes not directly related to the items covered in this article.
</p>
<h5>Code Cleanup</h5>
<p>To make adding the code for this section easier and to make the code more reusable I have moved some of the code from the
<b>GameEngine</b> class into separate classes such as <b>Camera</b>. Encapsulating the camera functionality in a separate object makes the code easer to change and to read. The following changes have already been integrated into the code for this article.
</p>
<ol>
<li>I moved the <b>FrameworkTimer</b> class out of the DirectX support code into a class called
<b>HiResTimer</b> and removed the <b>using</b> statements for <b>Microsoft.Samples.DirectX.UtilityToolkit</b>. For the VB version I converted the
<b>FrameworkTimer</b> class into VB and removed the reference to the DirectX Sample Framework library.
</li><li>I refactored the device creation code in the constructor of the <b>GameEngine</b> class into the
<b>ConfigureDevice</b> method. </li><li>I refactored all code that deals with the device in the <b>OnPaint</b> method of the
<b>GameEngine</b> class into the <b>Render</b> method. </li><li>I refactored the code that sets up the camera in the <b>OnPaint</b> method of the
<b>GameEngine</b> class into the <b>Camera</b> class. </li><li>I removed the <b>CreateCrossHairVertexArrayTop</b>, <b>CreateCrossHairVertexArrayBottom,</b>
<b>CreateTestTriangle</b>, and <b>CreateTestCube</b> methods from the <b>GameEngine</b> Class.
</li><li>Removed the <b>System.Collections.Generic</b>, <b>System.ComponentModel</b>, <b>
System.Data</b> and <b>System.Text</b> using statements from the <b>GameEngine</b> class.
</li><li>I removed all of the code used for experimenting with the camera settings. </li></ol>
<p>In addition to these general housekeeping changes I added some code that I needed to make the DirectInput portion more interesting.
</p>
<h5>Skybox</h5>
<p>The infinite 3D space we have created has one problem: it's infinite. We have no distinguishing terrain features to orient us and, as such, have no idea in which direction we are facing. We could create a number of complex 3D objects to draw a realistic
 terrain, but this is very slow and we really do not need 'real' terrain, but only to create the look of real terrain. To create this illusion of seeing a horizon and terrain in the distance, we make use of a technique called the skybox. A skybox creates the
 effect you get when placing your head into a cardboard box, the inside of which is painted with a landscape: Regardless where you are and where you look you see the inside of the box and nothing else.
</p>
<p>In our game we create a cube and display textures (or pictures for us that prefer to use more normal definitions) on the inside walls of the cube. The top would be textured like the sky, the bottom like the ground and the remaining four sides have a texture
 applied to them that shows a horizon and terrain. The pictures for the four sides are designed in such a manner that they match perfectly at the edges and produce a seamless landscape. These four sides could then represent cardinal directions such as east,
 west, north and south (if your game is set on Earth). </p>
<p>To achieve the correct effect, we need to ensure that all objects are drawn on top of the skybox. This is done by disabling Z-buffering before drawing the skybox and enabling it after we are done.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.RenderState.ZBufferWriteEnable = <span class="kwrd">false</span>; <br><span class="rem">// draw the skybox here </span><br>_device.RenderState.ZBufferWriteEnable = <span class="kwrd">true</span>;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"></pre>
<pre class="csharpcode">_device.RenderState.ZBufferWriteEnable = <span class="kwrd">False</span><br><span class="rem">'draw the skybox here</span><br>_device.RenderState.ZBufferWriteEnable = <span class="kwrd">True</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The next thing we need to ensure is that the player can never actually get close to or beyond the skybox (otherwise they would notice the illusion). We accomplish this by ensuring that the viewpoint is always in the center of the skybox.
</p>
<p>First we assign an Identity matrix to the world matrix. Since the vertices of the skybox are in model space (offset around zero), this ensures that they are not translated into world space. Then we set the use the View matrix of the camera to set the View
 matrix of the skybox. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">Matrix worldMatrix = Matrix.Identity;<br>Matrix viewMatrix = cam.View;<br><br>viewMatrix.M41 = 0.0f;<br>viewMatrix.M42 = 0.0f;<br>viewMatrix.M43 = 0.0f;<br><br>_device.Transform.View = viewMatrix;<br>_device.Transform.World = worldMatrix;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Dim</span> worldMatrix <span class="kwrd">As</span> Matrix = Matrix.Identity<br><span class="kwrd">Dim</span> viewMatrix <span class="kwrd">As</span> Matrix = cam.View<br>viewMatrix.M41 = 0.0F<br>viewMatrix.M42 = 0.0F<br>viewMatrix.M43 = 0.0F<br>_device.Transform.View = viewMatrix<br>_device.Transform.World = worldMatrix</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Drawing the actual skybox uses the techniques we have discussed in the previous articles and I am not going to cover them in detail. The basic steps are as follows.
</p>
<ol>
<li>Define a <b>PositionNormalTextured</b> vertex array to hold the data for the four corners of each cube face and texture information.
</li><li>Load the texture for each cube face from a file. </li><li>Setup the <b>Vertex</b> buffer for each face. </li><li>On each <b>Render</b> loop readjust the skybox. </li><li>On each <b>Render</b> loop disable Z-buffering. </li><li>On each <b>Render</b> loop use the <b>Camera</b> object passed in to determine the direction the camera is facing and draw the appropriate face.
</li><li>On each <b>Render</b> loop turn Z-buffering back on. </li></ol>
<p>If you look at the <b>RenderFace </b>method of the <b>SkyBox</b> class, you will notice that it is identical to the code we used to draw the triangle and cube in the last article.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.SetStreamSource ( 0, faceVertexBuffer, 0 );<br>_device.VertexFormat = CustomVertex.PositionNormalTextured.Format;<br>_device.SetTexture ( 0, faceTexture );<br>_device.DrawPrimitives ( PrimitiveType.TriangleStrip, 0, 2 );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.SetStreamSource(0, faceVertexBuffer, 0)<br>_device.VertexFormat = CustomVertex.PositionNormalTextured.Format<br>_device.SetTexture(0, faceTexture)<br>_device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2)</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h5>Camera Class</h5>
<p>The other major refactoring I did for this article is to move all the camera-related code into the
<b>Camera</b> class. The fixed values such as FoV and aspect ratio used in the <b>
Perspective</b> matrix are set as internal properties with the appropriate default values. I have also added methods that allow the camera to be moved left or right and up or down, and a method that moves the position of the camera. Why I added these methods
 will become clear once we integrate user input later in the article. </p>
<p>Now that all of the graphics for the game except the enemy units are done, let's get the tank moving so we can explore our new world.
</p>
<h5>Controlling Input</h5>
<p>Controlling input devices is not nearly as cool as graphics manipulation or artificial intelligence, but without it you couldn't have a game. Reacting to user input allows the user to move around in and manipulate the 3D world we have created.
</p>
<p>The DirectInput API allows you to control the mouse, keyboard, joystick, game-pad, or force feedback device. Some games also provide the ability for voice input to control the game, but that is beyond the scope of our game.
</p>
<h5>Adding DirectInput</h5>
<p>The first step when adding input support to an application is to reference the
<b>Microsoft.DirectX.DirectInput.dll</b> assembly. The next step is to add the using statement to each class in which you plan to use the DirectInput classes (unless you really like typing).
</p>
<h5>Detecting Devices</h5>
<p>A good API provides a common way to access similar devices. This is true in DirectX where physical devices such as video cards, sound cards, and input devices are abstracted into the
<b>Device</b> class. This class shields us as developers from knowing any of the hardware-specific details. In the DirectInput namespace a Device represents any of the potential input devices.
</p>
<p>Another familiar construct is the <b>Manager</b> class. We used the <b>Manager</b> class from the Direct3D namespace to get information about the adapters and to retrieve device capabilities for each adapter. In DirectInput the process is very similar.
</p>
<p>To get a list of specific devices such as all keyboards connected to the computer, you use the
<b>GetDevices</b> method of the Manager class and pass in the DeviceClass or DeviceType and one of the EnumDevicesFlags enumeration values to filter the list further. A computer can have many input devices but as a minimum it should have a keyboard and mouse.
</p>
<p><b>Note:</b> Most of the time you are going to use <b>EnumDevicesFlags.AttachedOnly</b> to get only the attached devices of a particular type.
</p>
<p>To make things a little more obscure, a mouse is considered a Pointer type in the
<b>DeviceClass</b> enumeration. You can use any combination of to retrieve a custom list of input devices.
</p>
<p>Each call to <b>GetDevices</b> returns a <b>DeviceList</b> class. This <b>DeviceList</b> in turn contains a
<b>DeviceInstance</b> structure for each device. The <b>DeviceInstance</b> structure contains the information about each device, the most important of which is the
<b>InstanceGuid</b>. This is a unique identifier for each device on our system that we need to know so we can communicate with that device.
</p>
<p><b>Note: </b>Just because a device is in the <b>DeviceList</b> does not mean that it is actually attached. You can use the
<b>InstanceGuid</b> and the <b>GetDeviceAttached</b> method to determine if the device is attached.
</p>
<p>The Manager class exposes a <b>Devices</b> property that contains a <b>DeviceList</b>.
</p>
<p>Note that the <b>DeviceInstance</b> structure is not actually a device; there is nothing we can do with it in terms of connecting to it. The only use it has is to provide a GUID which we can then use to actually connect to or acquire that device.
</p>
<h5>Connecting to a Keyboard</h5>
<p>The first device we are going to connect to is the keyboard. This is probably the most common device used to interact with games. Most modern games enable the user to control the game using the keyboard and the mouse, as there are too many actions to perform
 to use just one of these devices. Depending on your audience, you need to choose the primary input device and decide whether to offer configurable choices for secondary devices. You also need to remember that some computers, such as slate-mode Tablet PCs,
 have no keyboard, so offering alternate input means broadens your potential audience.
</p>
<p>Regardless of what input options you offer, the steps to set up any input device are the same.
</p>
<ol>
<li>Instantiate a <b>Device</b> class passing the type of device. </li><li>Set the cooperation level of the device. </li><li>Set the format of the data returned for the device. </li><li>Acquire the device. </li><li>Poll the device. </li><li>Read the state data to determine what actions the user did. </li></ol>
<p>Using good OO practices, we first create a keyboard class that will encapsulate all keyboard-specific functionality and provide a single access point for the rest of the game to any keyboard functionality.
</p>
<p>The first step is to create a <b>Device</b> object for the keyboard. We do this using the Keyboard value of the
<b>SystemGuid</b> enumeration. This lets us connect to the default keyboard. Using the default keyboard is safer than enumerating the devices and picking a specific one, because you don't know beforehand what devices all your users might have.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device = <span class="kwrd">new</span> Device ( SystemGuid.Keyboard );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device = <span class="kwrd">New</span> Device(SystemGuid.Keyboard)</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The next step is to set the Cooperative level of the device. The values of the
<b>CooperativeLevelFlags</b> enumeration determine how much control we chose to take over the device and how much control we leave to other applications.
</p>
<p>The <b>CooperativeLevelFlags</b> enumeration contains five values. </p>
<ul>
<li>Exclusive </li><li>NonExclusive </li><li>Foreground </li><li>Background </li><li>NoWindowsKey </li></ul>
<p>The <b>Background</b> and <b>Foreground</b> values are mutually exclusive, as are the
<b>Exclusive</b> and <b>NonExclusive</b> values. The <b>Foreground</b> option states that we only want data from the device if the window we passed into the
<b>SetCooperativeLevel</b> method has the focus. The <b>Background</b> option simply means that we always want data from the device.
<b>Exclusive</b> means that we want priority for control of the device while <b>NonExclusive</b> means we don't. Even when using the
<b>Exclusive</b> option it is still possible to lose the device, which is why we add the reacquire logic to the
<b>Poll</b> method to ensure we can get the device back when we want to read its state. The
<b>NoWindowsKey</b> option can be combined with any of the other settings and specifies that we want to ignore the Windows logo key on the keyboard. This setting is important when running in full screen mode, because the Windows key causes the application to
 loose focus. </p>
<p>For BattleTank 2005 we combine the <b>Background </b>and <b>NonExclusive</b> values to allow other applications maximum control over this device.
</p>
<p>We also need to pass in a reference to the window we are using so DirectX knows which window's input we are interested in.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.SetCooperativeLevel ( form, CooperativeLevelFlags.Background | <br>    CooperativeLevelFlags.NonExclusive ); </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"></pre>
<pre class="csharpcode"></pre>
<pre class="csharpcode">_device.SetCooperativeLevel(form, CooperativeLevelFlags.Background Or _ <br>    CooperativeLevelFlags.NonExclusive)</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The next step is to determine the data format we expect this device to return. We cover the contents of this data structure a little later in the article.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.SetDataFormat ( DeviceDataFormat.Keyboard ); </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.SetDataFormat(DeviceDataFormat.Keyboard)</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The last step is to actually acquire the device. You can think of this like opening a communications channel to the device. Since there are lots of things that could go wrong at this point, it is best to wrap the
<b>Acquire</b> call into a try/catch block. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">try</span><br>{<br>    _device.Acquire ( );<br>}<br><span class="kwrd">catch</span> ( DirectXException ex )<br>{<br>    Console.WriteLine ( ex.Message );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Try</span><br>    _device.Acquire()<br><span class="kwrd">Catch</span> ex <span class="kwrd">As</span> DirectXException<br>    Console.WriteLine(ex.Message)<br><span class="kwrd">End</span> Try</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>After acquiring the device we can read its state, which is a byte array. The first 256 values of this array hold the state of the keyboard; the next 8, the state of the mouse; and the last 32, the state of the joystick. Setting the device data format simply
 restricts the returned array to the set of values for the specified device. The <b>
KeyboardState</b> structure, for example, only contains the first 256 bytes of the raw state.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> KeyboardState _state; </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> _state <span class="kwrd">As</span> KeyboardState</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>To get this state from the device we first call the <b>Poll</b> method. This method communicates with the actual hardware. Then we copy the state into a local data structure (the
<b>_state </b>variable). </p>
<p>Since we are going to do this on every frame, I placed this particular sequence of calls into their own public method called
<b>Poll</b>. In the game loop we then call _<code>keyboard.Poll()</code> and use the state data structure to see what keys were pressed. This is where we deal with a device which may have been acquired by another application by attempting to reacquire it.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">try</span><br>{<br>    _device.Poll ( );<br>    _state = _device.GetCurrentKeyboardState ( );<br>}<br><span class="kwrd">catch</span> ( NotAcquiredException )<br>{<br>    <span class="rem">// try to reqcquire the device</span><br>    <span class="kwrd">try</span><br>    {<br>        _device.Acquire ( );<br>    }<br>    <span class="kwrd">catch</span> ( InputException iex )<br>    {<br>        Console.WriteLine ( iex.Message );<br>        <span class="rem">// could not get the device</span><br>    }<br>}<br><span class="kwrd">catch</span> ( InputException ex2 )<br>{<br>    Console.WriteLine ( ex2.Message );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Try</span><br>    _device.Poll()<br>    _state = _device.GetCurrentKeyboardState<br><span class="kwrd">Catch</span> generatedExceptionVariable0 <span class="kwrd">As</span> NotAcquiredException<br>    <span class="kwrd">Try</span><br>        _device.Acquire()<br>    <span class="kwrd">Catch</span> iex <span class="kwrd">As</span> InputException<br>        Console.WriteLine(iex.Message)<br>    <span class="kwrd">End</span> <span class="kwrd">Try</span><br><span class="kwrd">Catch</span> ex2 <span class="kwrd">As</span> InputException<br>    Console.WriteLine(ex2.Message)<br><span class="kwrd">End</span> <span class="kwrd">Try</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The only step remaining is to examine the state data returned to see what actions the user performed.
</p>
<p>In addition to managing the device state each time we poll the device, we want to make sure to release it when we are finished using it. We accomplish this by calling the
<b>Unacquire</b> method of the device in the <b>Dispose</b> method. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> ( _device != <span class="kwrd">null</span> )<br>    _device.Unacquire ( );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> <span class="kwrd">Not</span> (_device <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>    _device.Unacquire()<br><span class="kwrd">End</span> If</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<h5>Connecting to a Mouse</h5>
<p>Connecting to a mouse is almost identical to connecting to a keyboard. The differences are the
<b>SystemGuid</b> passed to the <b>Device</b> constructor, the <b>DeviceDataFormat</b>, the data structure used to store the state information, and the method call used to retrieve the device state.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device = <span class="kwrd">new</span> Device ( SystemGuid.Mouse );<br>_device.SetDataFormat ( DeviceDataFormat.Mouse );<br><span class="kwrd">private</span> MouseState _state;<br><span class="kwrd">public</span> <span class="kwrd">void</span> Poll ( )<br>{<br>    _device.Poll ( );<br>    _state = _device.CurrentMouseState;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device = <span class="kwrd">New</span> Device(SystemGuid.Mouse)<br>_device.SetDataFormat(DeviceDataFormat.Mouse)<br><span class="kwrd">Private</span> _state <span class="kwrd">As</span> MouseState<br><span class="kwrd">Public</span> <span class="kwrd">Sub</span> Poll()<br>        _device.Poll()<br>        _state = _device.CurrentMouseState<br><span class="kwrd">End</span> <span class="kwrd">Sub</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Using the mouse also provides the ability to define how the X, Y and Z (No, don't pick up your mouse, the Z value is the value for the mouse scroll wheel on certain mice) values are reported on each poll. Setting the
<b>AxisModeAbsolute</b> value to true returns the coordinates in screen coordinates, while setting this value to false returns the change in pixels from the previous poll. We set this value as soon as we have acquired the device.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.Acquire ( );<br>_device.Properties.AxisModeAbsolute = <span class="kwrd">false</span>;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.Acquire()<br>_device.Properties.AxisModeAbsolute = <span class="kwrd">False</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Using the false option is valuable if you want to determine the speed in which the user moved the mouse using the time elapsed between polls and the distance traveled in that time frame while the first option is more valuable if the user is selecting something
 from the screen. </p>
<h5>Connecting to a Joystick</h5>
<p>Connecting to a joystick follows the same general steps as for the keyboard and mouse, but, since there is no such thing as a default joystick, no corresponding
<b>SystemGuid</b> value exists. Instead, we need to use the <b>GetDevices</b> method of the
<b>Manager</b> class, passing in <b>GameControl</b> type for the <b>DeviceClass</b> and
<b>AttachedOnly</b> for the <b>EnumDevicesFlags</b> to enumerate any attached joysticks. You would probably want to present some type of UI to the user to let them choose from a list of devices found or you could just use the first device as the code snippet
 does. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">DeviceList gameControllerList = <br>    Manager.GetDevices(<br>        DeviceClass.GameControl, <br>        EnumDevicesFlags.AttachedOnly);<br><br><span class="kwrd">if</span> (gameControllerList.Count &gt; 0)<br>{<br>    <span class="kwrd">foreach</span> (DeviceInstance deviceInstance <span class="kwrd">in</span> gameControllerList)<br>    {<br>        _device = <span class="kwrd">new</span> Device(deviceInstance.InstanceGuid);<br>        _device.SetCooperativeLevel(form,<br>            CooperativeLevelFlags.Background | <br>            CooperativeLevelFlags.NonExclusive);<br>        <span class="kwrd">break</span>;<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">Dim</span> gameControllerList <span class="kwrd">As</span> DeviceList<br>gameControllerList = Manager.GetDevices(DeviceClass.GameControl, _<br>    EnumDevicesFlags.AttachedOnly)<br><span class="kwrd">If</span> (gameControllerList.Count &gt; 0) <span class="kwrd">Then</span><br>    <span class="kwrd">Dim</span> deviceInstance <span class="kwrd">As</span> DeviceInstance<br>    <span class="kwrd">For</span> <span class="kwrd">Each</span> deviceInstance <span class="kwrd">In</span> gameControllerList<br>        _device = <span class="kwrd">New</span> Device(deviceInstance.InstanceGuid)<br>        _device.SetCooperativeLevel(Form, CooperativeLevelFlags.Background <br>        <span class="kwrd">Or</span> CooperativeLevelFlags.NonExclusive)<br>        Break()<br>    <span class="kwrd">Next</span><br><span class="kwrd">End</span> If</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The next step is to specify a new <b>DeviceDataFormat</b> and new type for the _<b>state</b> data structure. Finally you need to retrieve the joystick state from the device inside the
<b>Poll</b> method. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.SetDataFormat ( DeviceDataFormat.Joystick );<br><span class="kwrd">private</span> JoystickState _state;<br><span class="kwrd">public</span> <span class="kwrd">void</span> Poll ( )<br>{<br>    _device.Poll ( );<br>    _state = _device.CurrentJoystickState;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_device.SetDataFormat(DeviceDataFormat. Joystick)<br><span class="kwrd">Private</span> _state <span class="kwrd">As</span> JoystickState<br><span class="kwrd">Public</span> <span class="kwrd">Sub</span> Poll()<br>        _device.Poll()<br>        _state = _device.CurrentJoystickState<br><span class="kwrd">End</span> <span class="kwrd">Sub</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In BattleTank 2005 we are not going to use a joystick, but feel free to add this capability on your own if you have a joystick. If you own a force-feedback device you might also want to experiment with using it in the game.
</p>
<p>Now that we have access to the various forms of input devices, and know how to retrieve their state we need to know how to read the various state data structures to determine user actions.
</p>
<h5>Determining User Actions</h5>
<p>Each of the data structures for the state are byte arrays. The <b>KeyboardState</b> is a byte array 256 bytes long. Each byte represents the state of a key on the keyboard and the position in the array matches the value of the
<b>Key</b> enumeration. The indexer for the <b>KeyboardState</b> returns a Boolean value for each index checked. For example, to see if the user pressed the Escape key you simply test that the most significant bit is set at that index location (position 1 for
 Escape) in the array. If this expression returns true then the user pressed the Escape key, otherwise it returns false.
</p>
<p>Each poll method may return values for multiple keys such as when the user pressed certain key combinations (Ctrl&#43;Alt&#43;Delete is a common one for me when I program). DirectInput supports a maximum of five key values, but you should be nice to your users and
 stick to single key actions if possible. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_state[Key.Escape] </pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<p>&nbsp;</p>
<pre class="csharpcode"></pre>
<pre class="csharpcode">_keyboard.State(Key.Escape)</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>MouseState</b> is a structure that provides three public properties for the X, Y and Z values, as well an eight byte long array for the state of the mouse buttons that is retrieved by calling the
<b>GetMouseButtons</b> method. </p>
<p>Checking for the button information is the same for the mouse buttons as it was for the keyboard keys. You simply check the most significant bit at each position to determine if the corresponding button was pressed.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> ( 0 != mouseButtons[0])<br>    Console.WriteLine ( <span class="str">&quot;Primary Button pressed&quot;</span> );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> <span class="kwrd">Not</span> (0 = _mouse.MouseButtons(0)) <span class="kwrd">Then</span><br>    Console.WriteLine(<span class="str">&quot;Fire!&quot;</span>)<br><span class="kwrd">End</span> <span class="kwrd">If</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The 0 position represents the primary button which could be the left or right mouse button depending on how the user configured the mouse.
</p>
<p>Depending on the <b>AxisModeAbsolute</b> setting, the X, Y and Z values return the absolute or relative position of the mouse. Regardless of this setting the values for the X axis are always positive to the right and negative to the left, positive forward
 and negative backward for the Y value, and positive when spinning the scroll wheel forward and negative backward for the Z value.
</p>
<h5>Reacting to User Action</h5>
<p>Now that we can detect what the user is doing, it is time to take that input and use it to manipulate our world. First we create a method called
<b>CheckForInput</b> that will contain all of the input-related code. (In a later article I will show you why this is not the best way of tracking and reacting to user input and how a system called Action Mapping can be used to reduce the amount of code and
 avoid code duplication.) For right now we are going to set up BattleTank 2005 to use the cursor keys to change the heading and pitch of the camera (move it up/down and left/right). Note that this does not change the location of the camera. The first step is
 to poll the devices to retrieve the latest state information. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_keyboard.Poll ( );<br>_mouse.Poll ( );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">_keyboard.Poll()<br>_mouse.Poll()</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Then we test the state for the keys we are interested in and react accordingly.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> ( _keyboard.State[Key.LeftArrow] )<br>    _camera.MoveCameraLeftRight ( -0.5f );<br><br><span class="kwrd">if</span> ( _keyboard.State[Key.RightArrow] )<br>    _camera.MoveCameraLeftRight ( 0.5f );<br><br><span class="kwrd">if</span> ( _keyboard.State[Key.UpArrow] )<br>    _camera.MoveCameraUpDown ( -0.5f );<br><br><span class="kwrd">if</span> ( _keyboard.State[Key.DownArrow] )<br>    _camera.MoveCameraUpDown ( 0.5f );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> _keyboard.State(Key.LeftArrow) <span class="kwrd">Then</span><br>    _camera.MoveCameraLeftRight(-0.5F)<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">If</span> _keyboard.State(Key.RightArrow) <span class="kwrd">Then</span><br>    _camera.MoveCameraLeftRight(0.5F)<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">If</span> _keyboard.State(Key.UpArrow) <span class="kwrd">Then</span><br>    _camera.MoveCameraUpDown(-0.5F)<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">If</span> _keyboard.State(Key.DownArrow) <span class="kwrd">Then</span><br>    _camera.MoveCameraUpDown(0.5F)<br><span class="kwrd">End</span> <span class="kwrd">If</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>We also want to use the mouse to move the camera, so we add another set of checks for the mouse input.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> ( 0 != ( _mouse.State.X | _mouse.State.Y ) )<br>{<br>    _camera.MoveCameraLeftRight ( _mouse.State.X / 10 );<br>    _camera.MoveCameraUpDown ( _mouse.State.Y / 10 );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> <span class="kwrd">Not</span> (0 = (_mouse.State.X <span class="kwrd">Or</span> _mouse.State.Y)) <span class="kwrd">Then</span><br>    _camera.MoveCameraLeftRight(_mouse.State.X / 10)<br>    _camera.MoveCameraUpDown(_mouse.State.Y / 10)<br><span class="kwrd">End</span> <span class="kwrd">If</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>You can adjust the increments used in the <b>MoveCameraLeftRight</b> and <b>MoveCameraUpDown</b> methods to make the movement slower or faster.
</p>
<p>The final step is to add a key that enables us to exit the application. The Escape key is the natural choice:
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> ( _keyboard.State[Key.Escape] )<br>{<br>    Application.Exit ( );<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> _keyboard.State(Key.Escape) <span class="kwrd">Then</span><br>    Application.<span class="kwrd">Exit</span>()<br><span class="kwrd">End</span> <span class="kwrd">If</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In addition to moving the camera around, we also want to move the location of the camera since that is how we are going to simulate driving around in our tank. The only problem is that, with no fixed items in the world, we can't really tell when we have
 moved, since the only reference point is the skybox, which never changes position. To overcome this limitation until we add units in the next article, I am simply writing out the new camera location to the Console whenever it changes.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> ( _keyboard.State[Key.W] )<br>    _camera.MoveCameraPosition ( 10, 0, 0 );<br><br><span class="kwrd">if</span> ( _keyboard.State[Key.S] )<br>    _camera.MoveCameraPosition ( -10, 0, 0 );<br><br><span class="kwrd">if</span> ( _keyboard.State[Key.A] )<br>    _camera.MoveCameraPosition ( 0, 10, 0 );<br><br><span class="kwrd">if</span> ( _keyboard.State[Key.D] )<br>    _camera.MoveCameraPosition ( 0, -10, 0 );<br><br><span class="kwrd">if</span> ( oldX != _camera.X )<br>{<br>    Console.WriteLine ( _camera.X &#43; <span class="str">&quot;, &quot;</span> &#43; _camera.Y );<br>    oldX = _camera.X;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> _keyboard.State(Key.W) <span class="kwrd">Then</span><br>    _camera.MoveCameraPosition(10, 0, 0)<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">If</span> _keyboard.State(Key.S) <span class="kwrd">Then</span><br>    _camera.MoveCameraPosition(-10, 0, 0)<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">If</span> _keyboard.State(Key.A) <span class="kwrd">Then</span><br>    _camera.MoveCameraPosition(0, 10, 0)<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">If</span> _keyboard.State(Key.D) <span class="kwrd">Then</span><br>    _camera.MoveCameraPosition(0, -10, 0)<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">If</span> <span class="kwrd">Not</span> (oldX = _camera.X) <span class="kwrd">Then</span><br>    Console.WriteLine(_camera.X &amp; <span class="str">&quot;, &quot;</span> &amp; _camera.Y)<br>    oldX = _camera.X<br><span class="kwrd">End</span> <span class="kwrd">If</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The last piece of input-checking we need to add is checking the mouse buttons. For right now, let's assume that the default button on the mouse causes the tank to fire. We are going to add more exciting action later on, but all we can do now is to write
 &quot;Fire!&quot; to the Console. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">if</span> ( 0 != _mouse.MouseButtons[0] )<br>    Console.WriteLine ( <span class="str">&quot;Fire!&quot;</span> );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">If</span> <span class="kwrd">Not</span> (0 = _mouse.MouseButtons(0)) <span class="kwrd">Then</span><br>    Console.WriteLine(<span class="str">&quot;Fire!&quot;</span>)<br><span class="kwrd">End</span> <span class="kwrd">If</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>That's it for input. As I mentioned before, there are better ways of relating keyboard and mouse keys and movement to actions in the game. You may also notice that when moving the camera, sometimes a single button click causes two movements. This is due
 to the fact that the game loop is faster than we are and the key is pressed long enough to be picked up in two game loops. We are also going to fix that in the next article.
</p>
<h4>Summary</h4>
<p>Once again I find myself running out of space before being able to cover all of the items I wanted, but I hope there is enough stuff here to let you experiment on your own. We are going to continuously refine the game in each iteration rather than trying
 to get it perfect the first time; that is the sprit of Agile development. The important things to remember are how to use the Device class to acquire and then poll an input device, and how to determine the input from the State objects.
</p>
<p>Even though we are now able to maneuver through the 3D world, it is not very exciting, since other than the skybox there are no other items in our world. In the next article we are going to fix that by adding units, both stationary and mobile, and work on
 collision detection. We are also going to refine the camera to help us in reducing the number of items we need to render by tacking the frustum. Oh—yes, I do know that the targeting crosshairs are gone; they will be back in the next article in the form of
 a real Heads-Up-Display (HUD) class. </p>
<p>Until then: Happy coding. </p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:72ac796ea5bf46abb4ac9e7600d9662b">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IV-DirectInput</comments>
      <itunes:summary>



&amp;nbsp;
This is Part 4 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers the input device portion of DirectX, called DirectInput.



Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
3-6 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions,
DirectX SDK
Hardware: None
Download: 

C# Download
VB Download






Beginning Game Development Series


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III



Welcome to the fourth article on beginning game development. In this article we are going to cover the input device portion of DirectX, called DirectInput. Using DirectInput you can control joysticks, a mouse or the keyboard.
 
Before we start I need to cover a couple of items that were brought to my attention via feedback from the readers (thank you everyone for taking the time to do this) and changes not directly related to the items covered in this article.
 
Code Cleanup
To make adding the code for this section easier and to make the code more reusable I have moved some of the code from the
GameEngine class into separate classes such as Camera. Encapsulating the camera functionality in a separate object makes the code easer to change and to read. The following changes have already been integrated into the code for this article.
 

I moved the FrameworkTimer class out of the DirectX support code into a class called
HiResTimer and removed t</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IV-DirectInput</link>
      <pubDate>Fri, 03 Nov 2006 06:51:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IV-DirectInput</guid>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>23</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-IV-DirectInput/RSS</wfw:commentRss>
      <category>Gaming</category>
      <category>arcade</category>
    </item>
  <item>
      <title>Beginning Game Development: Part III - DirectX II</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This is Part 3 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers more advanced DirectX principles such as transforms, matrices, culling
 and clipping.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/windows/directx/default.mspx">DirectX SDK</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">None</span></div>
<div class="entry_details"><b>Download: </b></div>
<div class="entry_details">
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/940729/C4FBegDev3CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/940729/C4FBegDev3VB.msi">VB Download</a></li></ul>
</div>
<div class="entry_details"><strong>Beginning Game Development Series</strong></div>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
</td>
</tr>
</tbody>
</table>
</span>
<h4>Introduction</h4>
<p>Welcome to the third article on beginning game development. In this article we are going to cover some of the more advanced DirectX principles such as transforms, matrices, culling and clipping.
</p>
<p>Before we start, I need to cover a couple of items that were brought to my attention via feedback from the readers (thank you everyone for taking the time to do this) and changes not directly related to the items covered in this article.
</p>
<h5>Code Cleanup</h5>
<p>These changes have already been integrated into the code for this article. </p>
<ol>
<li>I updated to the June 2005 version DirectX SDK. I did have an issue with the DirectX assemblies being added to the Global Assembly Cache (GAC), so if you have any build errors, update the references to: C:\Program Files\Microsoft DirectX 9.0 SDK (June 2005)\Developer
 Runtime\x86\DirectX for Managed Code. </li><li>In the last article you surrounded the IsWindowed setting for the PresentParameters with a
<code>#if DEBUG</code> statement. To enable this option you must go to the Project settings and enable it:
<ul>
<li>Right-click the BattleTank2005 project and select Properties. </li><li>Select the Build tab. </li><li>In the general section, check the Define DEBUG constant option. </li></ul>
</li><li>Change the color in the <b>device.Clear</b> method call from DarkBlue to Black.
</li><li>Add the following code at the very end of the GameEngine constructor to make the form a more standard size.
</li></ol>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="rem">// force the window to a standard size</span>
<span class="rem">// the provides the correct aspect ratio of 1.33</span>
<span class="kwrd">this</span>.Size = <span class="kwrd">new</span> Size ( 800, 600 );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="rem">'force the window to a standard size</span>
<span class="rem">' the provides the correct aspect ratio of 1.33</span>
<span class="kwrd">Me</span>.Size = <span class="kwrd">New</span> Size(800, 600)<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<ol start="5">
<li>Change the Startup position of the form to CenterScreen.
<ul>
<li>Right-click the <b>GameEngine</b> form and select <b>View Designer.</b> </li><li>In Properties, change the <b>StartPosition</b> property to <b>CenterScreen</b></li></ul>
</li></ol>
<p>Now we can actually draw something on the screen and start creating the game. </p>
<h4>Drawing the targeting crosshairs.</h4>
<p>In BattleTank 2005 we are sitting inside of a tank and looking through the targeting scope at the world around us. We use the targeting crosshairs to make it easier to hit and destroy the enemy. In real life the crosshairs are fixed in the optics of the
 cannon, so they are always visible and located in the same spot when looking through the targeting scope as a Heads-up Display (HUD).
</p>
<p>In our game we have two choices when drawing the crosshairs. </p>
<ol>
<li>Draw them directly onto the center of the screen using screen coordinates. </li><li>Draw them using world coordinates and ensure that the view point is located such that they are visible and centered on the screen.
</li></ol>
<p>The tradeoff here is between speed and extensibility. If we choose the first option we do not have to transform the coordinates, since they are already in screen coordinates, which is faster. In effect, we are removing the targeting crosshairs from the model
 space we are creating. The downside is that if we chose to change the game later on and allow the player to leave the tank, the crosshairs would also be visible when they walk around. The second option requires the coordinates to be adjusted and transformed,
 but provides us with the ultimate flexibility to change the game later on. </p>
<p>I am going to use option 2 because it is the most flexible and I am not going to waste time trying to optimize the game for speed before knowing that it is slow. When you write a game you will be faced with design choices like this and you have to understand
 the tradeoffs you are making. </p>
<p>Before we move on, let's define a model that will make it easier to describe and (we hope) understand the terms we are going to cover in this article.
</p>
<h5>A Model</h5>
<p>Imagine an empty room. I determine where in the room the X, Y, Z origin is located. In this example let's say that the front left corner of the room is the origin in this world. This room becomes my
<b>World Space.</b> (A real world space is infinite, but for now we can make do with the finite space of the room.)
</p>
<p><b>World Space:</b> An infinite three-dimensional Cartesian space. You place your objects anywhere you want in this world to create the environment you want.
</p>
<p>Now I place a chair in the room at a predefined location. Each point on the chair can be accurately described using a set of Cartesian coordinates (X, Y, Z) and optional information about each point such as color (Color) and texture (Tu, Tv). If you think
 back to the last article you will notice that this makes each point a vertex. Since we have lots of separate vertices, we store all of them in a vertex array. When this array is loaded into memory it becomes a
<i>vertex buffer</i>. </p>
<h5>Vertex buffer</h5>
<p>Vertex buffers are ideally suited for the complex transformations that DirectX needs to perform. DirectX provides a number of predefined vertex types representing the most common vertex formats. These types are defined as structures in the
<b>CustomVertex</b> class. </p>
<p>We are going to use the <b>PositionColored</b> vertex for the targeting crosshairs. This vertex provides X, Y, Z properties and a
<b>Color</b> property, which is exactly what we need. This vertex also defines the coordinates' world space rather than screen space, which is what we decided to do.
</p>
<p>Add the following methods to the <b>GameEngine</b> class after the OnPaint method.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> CustomVertex.PositionColored[] CreateCrossHairVertexArrayTop ( )<br>{ <br>    CustomVertex.PositionColored[] crossHairs = <br>        <span class="kwrd">new</span> CustomVertex.PositionColored[7];<br>    <span class="kwrd">float</span> zval = 0f;<br>    <br>    <span class="rem">// top of targeting crosshairs</span>
    crossHairs[0].Position = <span class="kwrd">new</span> Vector3 ( -1f, 1f, zval );<br>    crossHairs[1].Position = <span class="kwrd">new</span> Vector3 ( -1f, 2f, zval );<br>    crossHairs[2].Position = <span class="kwrd">new</span> Vector3 ( 0f, 2f, zval );<br>    crossHairs[3].Position = <span class="kwrd">new</span> Vector3 ( 0f, 3f, zval );<br>    crossHairs[4].Position = <span class="kwrd">new</span> Vector3 ( 0f, 2f, zval );<br>    crossHairs[5].Position = <span class="kwrd">new</span> Vector3 ( 1f, 2f, zval );<br>    crossHairs[6].Position = <span class="kwrd">new</span> Vector3 ( 1f, 1f, zval );<br>    <br>    crossHairs[0].Color = Color.Green.ToArgb ( );<br>    crossHairs[1].Color = Color.Green.ToArgb ( );<br>    crossHairs[2].Color = Color.Green.ToArgb ( );<br>    crossHairs[3].Color = Color.Green.ToArgb ( );<br>    crossHairs[4].Color = Color.Green.ToArgb ( );<br>    crossHairs[5].Color = Color.Green.ToArgb ( );<br>    crossHairs[6].Color = Color.Green.ToArgb ( );<br>        <br>    <span class="kwrd">return</span> crossHairs;<br>}<br>    <br><span class="kwrd">private</span> CustomVertex.PositionColored[] CreateCrossHairVertexArrayBottom ()<br>{<br>    CustomVertex.PositionColored[] crossHairs = <br>        <span class="kwrd">new</span> CustomVertex.PositionColored[7];<br>    <br>    <span class="rem">// bottom of targeting crosshairs</span>
    <span class="kwrd">float</span> zval = 0f;<br>    <br>    <span class="rem">// bottom of targeting crosshairs</span>
    crossHairs[0].Position = <span class="kwrd">new</span> Vector3 ( 1f, -1f, zval );<br>    crossHairs[1].Position = <span class="kwrd">new</span> Vector3 ( 1f, -2f, zval );<br>    crossHairs[2].Position = <span class="kwrd">new</span> Vector3 ( 0f, -2f, zval );<br>    crossHairs[3].Position = <span class="kwrd">new</span> Vector3 ( 0f, -3f, zval );<br>    crossHairs[4].Position = <span class="kwrd">new</span> Vector3 ( 0f, -2f, zval );<br>    crossHairs[5].Position = <span class="kwrd">new</span> Vector3 ( -1f, -2f, zval );<br>    crossHairs[6].Position = <span class="kwrd">new</span> Vector3 ( -1f, -1f, zval );<br>    <br>    crossHairs[0].Color = Color.Green.ToArgb ( );<br>    crossHairs[1].Color = Color.Green.ToArgb ( );<br>    crossHairs[2].Color = Color.Green.ToArgb ( );<br>    crossHairs[3].Color = Color.Green.ToArgb ( );<br>    crossHairs[4].Color = Color.Green.ToArgb ( );<br>    crossHairs[5].Color = Color.Green.ToArgb ( );<br>    crossHairs[6].Color = Color.Green.ToArgb ( );<br>    <br>    <span class="kwrd">return</span> crossHairs;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> CreateCrossHairVertexArrayTop() <span class="kwrd">As</span> _<br>        CustomVertex.PositionColored()<br>    <span class="kwrd">Dim</span> crossHairs(7) <span class="kwrd">As</span> CustomVertex.PositionColored<br>    <span class="kwrd">Dim</span> zval <span class="kwrd">As</span> <span class="kwrd">Single</span> = 0.0F<br>    <span class="rem">' top of targeting crosshairs</span>
    crossHairs(0).Position = <span class="kwrd">New</span> Vector3(-1.0F, 1.0F, zval)<br>    crossHairs(1).Position = <span class="kwrd">New</span> Vector3(-1.0F, 2.0F, zval)<br>    crossHairs(2).Position = <span class="kwrd">New</span> Vector3(0.0F, 2.0F, zval)<br>    crossHairs(3).Position = <span class="kwrd">New</span> Vector3(0.0F, 3.0F, zval)<br>    crossHairs(4).Position = <span class="kwrd">New</span> Vector3(0.0F, 2.0F, zval)<br>    crossHairs(5).Position = <span class="kwrd">New</span> Vector3(1.0F, 2.0F, zval)<br>    crossHairs(6).Position = <span class="kwrd">New</span> Vector3(1.0F, 1.0F, zval)<br><br>    crossHairs(0).Color = Color.Green.ToArgb()<br>    crossHairs(1).Color = Color.Green.ToArgb()<br>    crossHairs(2).Color = Color.Green.ToArgb()<br>    crossHairs(3).Color = Color.Green.ToArgb()<br>    crossHairs(4).Color = Color.Green.ToArgb()<br>    crossHairs(5).Color = Color.Green.ToArgb()<br>    crossHairs(6).Color = Color.Green.ToArgb()<br><br>    <span class="kwrd">Return</span> crossHairs<br><span class="kwrd">End</span> <span class="kwrd">Function</span>
<span class="kwrd">Private</span> <span class="kwrd">Function</span> CreateCrossHairVertexArrayBottom() <span class="kwrd">As</span> _<br>        CustomVertex.PositionColored()<br>    <span class="kwrd">Dim</span> crossHairs(7) <span class="kwrd">As</span> CustomVertex.PositionColored<br><br>    <span class="rem">' bottom of targeting crosshairs</span>
    <span class="kwrd">Dim</span> zval <span class="kwrd">As</span> <span class="kwrd">Single</span> = 0.0F<br><br>    <span class="rem">' bottom of targeting crosshairs</span>
    crossHairs(0).Position = <span class="kwrd">New</span> Vector3(1.0F, -1.0F, zval)<br>    crossHairs(1).Position = <span class="kwrd">New</span> Vector3(1.0F, -2.0F, zval)<br>    crossHairs(2).Position = <span class="kwrd">New</span> Vector3(0.0F, -2.0F, zval)<br>    crossHairs(3).Position = <span class="kwrd">New</span> Vector3(0.0F, -3.0F, zval)<br>    crossHairs(4).Position = <span class="kwrd">New</span> Vector3(0.0F, -2.0F, zval)<br>    crossHairs(5).Position = <span class="kwrd">New</span> Vector3(-1.0F, -2.0F, zval)<br>    crossHairs(6).Position = <span class="kwrd">New</span> Vector3(-1.0F, -1.0F, zval)<br><br>    crossHairs(0).Color = Color.Green.ToArgb()<br>    crossHairs(1).Color = Color.Green.ToArgb()<br>    crossHairs(2).Color = Color.Green.ToArgb()<br>    crossHairs(3).Color = Color.Green.ToArgb()<br>    crossHairs(4).Color = Color.Green.ToArgb()<br>    crossHairs(5).Color = Color.Green.ToArgb()<br>    crossHairs(6).Color = Color.Green.ToArgb()<br><br>    <span class="kwrd">Return</span> crossHairs<br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Remember that the coordinates for the <b>Position</b> property of each vertex are defined in world space coordinates. We will transform them to screen coordinates in a while. Also note that you must call the
<b>ToArgb</b> method to convert <b>Color</b> to the 32-bit integer format required by DirectX.
</p>
<p>Before we continue we need to let the device know which type of vertex we chose. We accomplish this by setting the
<b>VertexFormat</b> property of the <b>Device</b> class to the <b>Format</b> property of the vertex we used. This property determines the
<i>fixed function pipeline</i> the device will use. Don't worry what exactly that is for right now; you just need to know that we are using the
<i>position</i> <i>and</i> <i>colored</i> pipeline. </p>
<p>In the <b>OnPaint</b> method, immediately following the <b>device.Clear</b> method add the following code.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.VertexFormat = CustomVertex.PositionColored.Format;<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.VertexFormat = CustomVertex.PositionColored.Format</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>With the crosshairs defined, we must now tell the device to actually render the object described in the vertex buffer to the screen. This is accomplished using the
<b>DrawUserPrimitives</b> method of the device class. So what are Primitives? </p>
<h5>Drawing Primitives</h5>
<p>Drawing Primitives are collections of vertices that define a single three-dimensional object. There are six primitives in DirectX listed in the
<b>PrimitiveType</b> enumeration. </p>
<ol>
<li><b>Line List:</b> Mainly used for adding Heads-up Display (HUD) information to a screen. The primitive count is equal to the number of points divided by two. The number of points must be even for this type to work.
</li><li><b>Line Strip:</b> This has the same uses as the Line List but renders a single continuous line. The primitive count is equal the number of vertices minus 1.
</li><li><b>Point List:</b> Mainly used for rendering individual points in particle images such as explosions or stars in the night sky. The primitive count is equal to the number of points in the vertex buffer.
</li><li><b>Triangle Fan:</b> This is most useful when drawing an oval object. </li><li><b>Triangle List:</b> This is the most commonly used primitive. The primitive count is the number of vertices divided by three,
</li><li><b>Triangle Strip:</b> These are most useful when rendering rectangular objects.
</li></ol>
<p>In our case we choose the <b>LineStrip</b> type to draw the crosshairs to the screen since it is an HUD. In the
<b>OnPaint</b> method, immediately following the <b>device.Clear</b> method add the following code.
</p>
<p><b>Visual C#</b></p>
<pre class="csharpcode">device.DrawUserPrimitives ( PrimitiveType.LineStrip, 6, <br>    CreateCrossHairVertexArrayTop ( ) );<br>device.DrawUserPrimitives ( PrimitiveType.LineStrip, 6, <br>    CreateCrossHairVertexArrayBottom ( ) );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.DrawUserPrimitives(PrimitiveType.LineStrip, 6, _<br>    CreateCrossHairVertexArrayTop())<br>device.DrawUserPrimitives(PrimitiveType.LineStrip, 6, _<br>    CreateCrossHairVertexArrayBottom())</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The <b>DrawUserPrimitives</b> method requires us to pass in the <b>PrimitiveType</b>, the count of primitives to render, and the source of the vertex data for the object. Since we are using the
<b>LineStrip</b> primitive, the seven points in each vertex buffer create six lines.
</p>
<p>Up to this point we have not actually drawn anything to the screen, just cleared the device; so we need to tell the device that we are planning to do so. This is accomplished with the
<b>BeginScene</b> method of the device class. </p>
<h5>Begin Scene/End Scene</h5>
<p>As I mentioned in the first article, there are a lot of correlations between movies and a DirectX game. The first we encountered was frame. Now we are going to add Scenes and little later a camera.
</p>
<p>We use the <b>BeginScene</b> and <b>EndScene</b> methods of the device to define the starting and ending points of a scene. The
<b>BeginScene</b> method prepares the device for the actions that follow by locking the back buffer. The
<b>EndScene</b> method tells the device that we are finished drawing and unlocks the back buffer. You must always call
<b>EndScene</b> after calling <b>BeginScene</b> otherwise the back buffer will remain locked. The
<b>BeginScene</b> and <b>EndScene</b> methods work closely together with the <b>Present</b> method to mange the back buffer; if one of these method calls fails the others will fail also.
</p>
<p>In the <b>OnPaint</b> method of the <b>GameEngine</b> class, add calls to <b>BeginScene</b> and
<b>EndScene</b>. The call to <b>BeginScene</b> needs to occur immediately after the
<b>Clear</b> method call. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Clear ( ClearFlags.Target, Color.Black, 1.0f, 0 );<br><span class="rem">// Tell DirectX we are about to draw something</span>
device.BeginScene ( );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Clear(ClearFlags.Target, Color.Black, 1.0F, 0)<br><span class="rem">' Tell DirectX we are about to draw something</span>
device.BeginScene()
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>And the <b>EndScene</b> method needs to be called immediately before the <b>Present</b> method call.
</p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="rem">// Tell DirectX that we are done drawing</span>
device.EndScene ( );
<span class="rem">// Flip the back buffer to the front</span>
device.Present ( );</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="rem">' Tell DirectX that we are done drawing</span>
device.EndScene()
<span class="rem">' Flip the back buffer to the front</span>
device.Present()
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now we are almost done. The last step remaining is to convert the world coordinates of each three-dimensional object into screen coordinates.
</p>
<p>In the last article we covered a lot of the DirectX terminology you need to understand. We are almost done with new terms, but before we can successfully render a 3-D world to the screen we need to cover one last set of definitions.
</p>
<h5>Lights, Camera, Action</h5>
<p>In our model we have described each point on the chair using Cartesian coordinates and a color value and stored these points in a vertex buffer. But DirectX still can't render the chair for me. Why? The missing pieces of information are our location in the
 room and the direction we are looking. We also need to determine how to handle the projection. Only with this information can the 3-D world be converted into the 2-D picture displayed on the screen.
</p>
<p>In DirectX our (the viewer's) location is called the camera location and it is defined by the
<i>View Matrix</i>. From now on consider the terms <i>view</i> and <i>camera</i> to be synonymous. The projection is the way distance is applied to the objects and can be compared to the lens setting of the camera.
</p>
<p>Cameras are very powerful tools in creating cool 3-D games. You can attach the camera to a moving object to get the feeling of actually being inside, or offset it slightly to the rear to get a chase view. You can also set up multiple static cameras in your
 world and view the action by switching from camera to camera. </p>
<p>All of the computations involved in converting the world coordinates to screen coordinates are performed used a
<i>Matrix</i>. These computations are called <i>Transforms</i>. Almost all of the heavy lifting performed in DirectX is the transformation of coordinates using Matrices.
</p>
<p><b>Transforms</b> (<a href="http://en.wikipedia.org/wiki/Transformation_%28mathematics%29">http://en.wikipedia.org/wiki/Transformation_%28mathematics%29</a>): Transformations change the coordinates of three-dimensional objects based on the view, projection
 type and world transform specified. These transformations are accomplished via a set of 4x4 matrices.
</p>
<p><b>Matrix</b> (<a href="http://en.wikipedia.org/wiki/Matrix_%28mathematics%29">http://en.wikipedia.org/wiki/Matrix_%28mathematics%29</a>): A rectangular table of numbers that is very efficient in transformations.
</p>
<p>You could spend a lot of time understanding the exact details of transformations with matrices. Understanding how they work is important, but you will not have to perform any manual calculations on your own, so we can skip the details for now. The
<b>Matrix</b> class contains a number of the most common methods for manipulating matrices.
</p>
<p>The first step is placing and orienting the camera in our three-dimensional world.
</p>
<h4>View Transform</h4>
<p>The view matrix defines the location of the camera and the orientation of the camera (by specifying a target). The view matrix also includes a value to determine which direction is considered to be up in our world. This is almost always the Y axis. You can
 either define your own matrix or use the built-in <b>Matrix.LookAtLH</b> and <b>
Matrix.LookAtRH</b> methods. Since we are using the left handed coordinate system we naturally use the
<b>LookAtLH</b> method (LH stands for Left Handed). Even if you do not explicitly define a view, then DirectX uses a default view.
</p>
<p>In the <b>OnPaint</b> method of the <b>GameEngine</b> class, add the following code immediately after the
<b>device.Clear</b> method call. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Transform.View = Matrix.LookAtLH(<span class="kwrd">new</span> Vector3 (0, 0, 5f), <br>    <span class="kwrd">new</span> Vector3(0, 0, 0), <span class="kwrd">new</span> Vector3(0, 1, 0));</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Transform.View = Matrix.LookAtLH(<span class="kwrd">New</span> Vector3(0, 0, 5.0F), _<br>    <span class="kwrd">New</span> Vector3(0, 0, 0), <span class="kwrd">New</span> Vector3(0, 1, 0))<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In Battle Tank 2005 we are placing the camera at the origin (0,0) and slightly forward on the Z axis. We then point the camera at the origin, and identify the Y axis as up by providing a value for Y.
</p>
<p>After placing and orienting the camera we need to define the projection we are going to use.
</p>
<h4>Projection Transform</h4>
<p>In DirectX there are two types of projections to choose from: </p>
<ul>
<li>Perspective (<a href="http://en.wikipedia.org/wiki/Perspective">http://en.wikipedia.org/wiki/Perspective</a>)
</li><li>Orthogonal (<a href="http://en.wikipedia.org/wiki/Orthogonal_projection">http://en.wikipedia.org/wiki/Orthogonal_projection</a>)
</li></ul>
<p>The Perspective projection is the most commonly used projection and is how humans see the world. In this projection objects appear smaller the further away from us they are and become deformed at some distance (like a road appears to converge toward the
 horizon). </p>
<p>Orthogonal projection, on the other hand, ignores distance (the Z value) so items retain their size regardless of their distance from the camera.
</p>
<p>We are going to use the Perspective Projection in BattleTank 2005. The projection determines how the vertices of the objects in the viewing frustum (<a href="http://en.wikipedia.org/wiki/Viewing_frustum">http://en.wikipedia.org/wiki/Viewing_frustum</a>)
 are transformed. The viewing frustum defines the three-dimensional space in which objects are visible to the camera. You can visualize this as a pyramid with the top cut off. The base of the pyramid is the far plane, the top the near plane, and the field of
 view is the angle at the apex. To perform this transformation we need to know four pieces of information.
</p>
<ol>
<li><b>Field of View (FoV):</b> This is typically 45 degrees or ¼ of <i>p</i> (Math.PI / 4). Reducing the FoV value is like zooming in on the scene, while a larger FoV value is like zooming out. A value greater then 45 degrees is like looking at the scene through
 a fisheye lens. </li><li><b>Aspect Ratio:</b> This is identical to the aspect ratio of your TV or Monitor and is always calculated as the viewport Width/Height. The viewport is nothing other than the form onto which we are rendering the game. Standard aspect ratios for computer
 screens are 1.33 (640x480 or 1280x1024). </li><li><b>Near Clipping Plane:</b> Objects closer to the camera than this plane are not rendered.
</li><li><b>Far Clipping Plane:</b> Objects beyond this plane are not rendered.
<p><b>Radians</b> (<a href="http://en.wikipedia.org/wiki/Radian">http://en.wikipedia.org/wiki/Radian</a>): In DirectX most angles are expressed as radians rather than degrees. To convert from degrees to radians, simple multiply the degree value by
<i>p</i>/180, where <i>n</i> is the measure of the angle in degrees. The DirectXDX library contains helper functions to perform the conversion for you in the
<b>Geometry</b> class. </p>
</li></ol>
<p>Using these values and some fancy math, DirectX transforms the vertices of each object from world coordinates to screen coordinates. To a certain extent, this transformation is what we do in our heads when we draw a picture of a three-dimensional space.
 We draw distant objects smaller, even though the actual object has not really changed its size, and we distort objects further away.
</p>
<p>In the <b>OnPaint </b>method of the <b>GameEngine </b>class, add the following code immediately after the
<b>device.Transform.View</b> method call added in the previous step. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Transform.Projection = Matrix.PerspectiveFovLH ( (<span class="kwrd">float</span>)Math.PI / <br>    4, <span class="kwrd">this</span>.Width / <span class="kwrd">this</span>.Height, 1.0f, 100.0f);</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Transform.Projection = Matrix.PerspectiveFovLH ((<span class="kwrd">single</span>)Math.PI / _<br>    4, <span class="kwrd">Me</span>.Width / <span class="kwrd">Me</span>.Height, 1.0f, 100.0f)</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>For BattleTank 2005 we used the traditional setting for the FoV of 45 degrees. Next we set the aspect ratio base and then define the viewing frustum as between 1 and 100 in our world coordinate space. The values for the clipping planes define the size of
 our visible world and can represent anything we want. One unit equals 10 meters in BattleTank 2005 so we have a 1 kilometer playing field.
</p>
<p>At this point you have to use some common sense when defining the viewing frustum. We could easily declare that each unit equals one kilometer, making the viewable area 100 kilometers deep. However, if we make the tanks regular size, you will never be able
 to see them beyond a couple of kilometers, so why waste resources rendering them to the screen if the player cannot see them?
</p>
<p>While the View and Projection Matrices describe the camera and camera lens, the world transformation matrix converts the model space coordinates into world space coordinates. These world space coordinates are then converted to screen coordinates in the View
 and Projection transforms. </p>
<h4>World Transform</h4>
<p>The last transform is a world transform. This transforms the object we are rendering from model space into world space.
</p>
<p>In a world transform you can move, rotate and scale each object. This transform applies to all objects drawn after setting the transform, until a new transform is specified.
</p>
<p><b>Model Space:</b> We define each object by defining each vertex with respect to the model.
</p>
<p>In BattleTank 2005 we are not going to use the World transform at this time, but I have included a transform in the code for this article that uses a test cube for you to experiment with. I suggest you play with changing the values for all three transforms
 and see how the results look on the screen. That is the easiest way to really understand what the various settings do. See the Experimenting section for details on how to do this.
</p>
<h4>Lights</h4>
<p>Whenever we draw a primitive using world coordinates, DirectX uses lighting to determine the color of each pixel. But since we have not yet defined a light source, we can simply turn the lights off at this time. If we do not turn lighting off, then DirectX
 assumes no lights are shining on the scene and renders each pixel as black. </p>
<p>In the <b>OnPaint</b> method of the <b>GameEngine </b>class, add the following code immediately after the
<b>device.Transform.Projection</b> method call added in the previous step. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="rem">// turn off the light source</span>
device.RenderState.Lighting = <span class="kwrd">false</span>;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="rem">' turn off the light source</span>
device.RenderState.Lighting = <span class="kwrd">False</span>
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In addition to controlling the lighting, the RenderState also allows us to control the culling behavior.
</p>
<h4>Culling</h4>
<p><i>Culling</i> is an operation that eliminates entire objects (unlike <i>clipping,</i> which removes only portions) from the scene that fall outside of the viewing frustum to reduce the total set of objects to render. The overall goal is of course speed;
 by eliminating the non essential objects the scene can be rendered faster. </p>
<p><b>Clipping:</b> Clipping discards portions of any single object that fall outside of the viewing frustum. Clipping is automatically managed by DirectX and requires no further intervention.
</p>
<p>When drawing a three-dimensional object, DirectX does not render the primitives (triangles) that comprise the faces of those objects that do not face the camera. This is called
<i>back face culling</i>. </p>
<p>DirectX determines which side of an object is facing the camera by using the order (winding) of the vertices. If you choose either clockwise or counterclockwise, then the vertices that are wound the opposite are on the back of the object and are culled.
 The default mode is counterclockwise culling, so you need to make sure to define your vertices in a clockwise order.
</p>
<p>The culling options are set in the <b>RenderState</b> by assigning one of the <b>
Cull</b> enumeration settings to the <b>device.RenderState.CullMode</b> property.
</p>
<p>In the <b>OnPaint </b>method of the <b>GameEngine </b>class, add the following code immediately after
<b>device.RenderState.Lighting</b> code added in the previous step. </p>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="rem">// Turn off backface culling</span>
device.RenderState.CullMode = Cull.None;</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"> <span class="rem">' Turn off backface culling</span>
device.RenderState.CullMode = Cull.None</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In the code that accompanies this article I have added a couple of extra items to make it easier for you to experiment with the various settings we just covered.
</p>
<h4>Experimenting</h4>
<p>To remove the HUD display, comment out the following lines: 122 and 123 (in VB.NET the lines are 92 and 93).
</p>
<p>You can also display a rotating cube by un-commenting lines 98, 101, 120 and commenting line 95 (VB.NET: 68, 71, 87, 90 and 65). You can change any of the values in the models or adjust the View, Projection and World transforms to see the effect of your
 changes. </p>
<p><b>Line Numbers: </b>To turn on line numbers, go to <b>Tools | Options | Text Editor | All Languages</b> and check the
<b>Line Numbers</b> box in the Display group. If you don't see the full options tree, just check the
<b>Show all Settings</b> option in the lower left of the Options dialog. </p>
<h4>Summary</h4>
<p>In these first three articles we have covered a lot of ground. The steps in the upcoming articles build upon the foundation laid in these first three articles. At this point you should know how to create a device and hook it to a Windows form and create
 a game loop using the <b>OnPaint</b> and <b>Invalidate</b> methods. You should be able to create and draw your own three-dimensional objects using vertex buffers and the
<b>DrawUserPrimitives</b> method, set up a camera, and transform the models into world space.
</p>
<p>If something is unclear at this time, you should review the links provided in the articles, the DirectX SDK, or go to one of the resources listed on the web. Once you have fully understood these principles, the rest of the game development process will be
 much easier. </p>
<p>With this knowledge you are ready to perform all but the most advanced operations in DirectX. The only steps required to add more objects to our world in BattleTank 2005 are to define them in model space, store them in a vertex buffer, and render them to
 the screen. As you imagine, complex objects consist of thousands of separate vertices, and defining them all in code is almost impossible, very error prone and extremely boring. So in the next article I will cover how to accomplish this task more efficiently.
 In the next article we are also going to finish of the last graphic pieces and then focus on controlling the tank using the classes in the DirectInput namespace.
</p>
<p>Until then: Happy coding!</p>
<span>]]&gt;</span> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:318ba75511114521905b9e7600d97270">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-III-DirectX-II</comments>
      <itunes:summary>



&amp;nbsp;
This is Part 3 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers more advanced DirectX principles such as transforms, matrices, culling
 and clipping.



Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions,
DirectX SDK
Hardware: None
Download: 


C# Download
VB Download

Beginning Game Development Series


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III








Introduction
Welcome to the third article on beginning game development. In this article we are going to cover some of the more advanced DirectX principles such as transforms, matrices, culling and clipping.
 
Before we start, I need to cover a couple of items that were brought to my attention via feedback from the readers (thank you everyone for taking the time to do this) and changes not directly related to the items covered in this article.
 
Code Cleanup
These changes have already been integrated into the code for this article.  

I updated to the June 2005 version DirectX SDK. I did have an issue with the DirectX assemblies being added to the Global Assembly Cache (GAC), so if you have any build errors, update the references to: C:\Program Files\Microsoft DirectX 9.0 SDK (June 2005)\Developer
 Runtime\x86\DirectX for Managed Code. In the last article you surrounded the IsWindowed setting for the PresentParam</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-III-DirectX-II</link>
      <pubDate>Fri, 03 Nov 2006 06:36:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-III-DirectX-II</guid>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>21</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-III-DirectX-II/RSS</wfw:commentRss>
      <category>Gaming</category>
      <category>arcade</category>
    </item>
  <item>
      <title>Beginning Game Development: Part II - Introduction to DirectX</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This is Part 2 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers the basics of DirectX.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/windows/directx/default.mspx">DirectX SDK</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">None</span></div>
<div class="entry_details"><b>Download: </b><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/940223/Intro_20to_20DirectX_20Code.msi">Download</a>
</div>
<div class="entry_details">&nbsp;</div>
<div class="entry_details"><strong>Beginning Game Development Series</strong></div>
<ol>
<li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a class="" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx " href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a class="" href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
</td>
</tr>
</tbody>
</table>
</span>
<h4>Introduction</h4>
<p>Welcome to the second article on beginning game development. In this article we are going to cover the basics of DirectX.
</p>
<p>DirectX is a multimedia API that provides a standard interface to interact with graphics and sound cards, input devices and more. Without this standard set of APIs you would have to write different code for each combination of graphics and sound cards and
 for each type of keyboard, mouse and joystick. DirectX abstracts us from the specific hardware and translates a common set of instructions into the hardware specific commands.
</p>
<p>Like all new tools, DirectX has a number of new terms and definitions that you need to understand. In addition to these new terms you also are going to have to brush up on your math skills. DirectX and game development in general is pretty math intensive,
 and it helps if you understand the basics. There is no need to get out the old calculator however, the idea is to understand the goal and the way to get to that goal, the rest we do in code with a number of pre-prepared math libraries.
</p>
<h4>DirectX Overview</h4>
<p>DirectX first appeared in 1995 and was then called the “GameSDK”. In its original form it was targeted at developers using C and C&#43;&#43;. Only with the release of the first managed version (9.0) of the API in December 2002 has it been possible to use C# or VB.NET
 with DirectX (actually you can use any CLR compliant language if you want to). </p>
<p>While much has been said and written about the performance of managed DirectX when compared to the unmanaged version, the fact that commercial games have already been created using managed DirectX should settle that argument once and for all. While certain
 games with extreme performance needs might need to use unmanaged code, most games can be created with managed code or using a mix of managed and unmanaged code. Writing in managed code makes the developers more productive and thus write more code and produces
 safer code. </p>
<p>After installing the DirectX SDK you should have a directory at C:\WINDOWS\Microsoft.NET\Managed DirectX with a subdirectory for each version of the SDK that has been installed on your machine. I am on my fourth version on the machine I am using and consequently
 I have four subdirectories. In each of these subdirectories you should have nine DLL and nine XML files. Since the managed world of .NET allows us to have multiple versions of the same DLL file on the same computer without causing the problems previously referred
 to as DLL-hell we can have multiple versions of the managed DirectX libraries available to us. This allows you to easily roll back to a previous version after installing a new version.
</p>
<p>If you have previous experience with DLL files in Windows you might be worried that having multiple versions of the same file installed on the same computer will cause problems. These versioning issues are no longer an issue since the introduction of side-by-side
 versioning in .NET.&nbsp; This means you can use the multiple versions to check for compatibility issues when a new version of the SDK is released without having to commit yourself to an upgrade.
</p>
<p>The nine DLL files roughly correspond to the ten namespaces in DirectX. As we create our game we'll use a number of these namespaces to provide support for input devices, sound, network play and of course 3D graphics.
</p>
<table class="" cellpadding="0" border="1">
<tbody>
<tr valign="top">
<td class="" width="50%"><b>Namespace</b></td>
<td class="" width="50%"><b>Description</b></td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX</td>
<td class="" width="50%">Common Classes and math Structures</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.Direct3D</td>
<td class="" width="50%">3D graphics and helper libraries</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.DirectDraw</td>
<td class="" width="50%">Direct Draw graphics API. This is a legacy namespace and you should not need to use it.</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.DirectPlay</td>
<td class="" width="50%">Networking API for multiplayer games</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.DirectSound</td>
<td class="" width="50%">Sound support</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.DirectInput</td>
<td class="" width="50%">Input device support (i.e mouse and joystick)</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.AudioVideoPlayback</td>
<td class="" width="50%">Play Video and Audio (i.e playback a DVD on your PC)</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.Diagnostics</td>
<td class="" width="50%">Troubleshooting</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.Security</td>
<td class="" width="50%">Access security</td>
</tr>
<tr valign="top">
<td class="" width="50%">Microsoft.DirectX.Security.Permissions</td>
<td class="" width="50%">Access security permissions</td>
</tr>
</tbody>
</table>
<p><b>Figure 1. List of DirectX 9.0 namespaces.</b> </p>
<p><b></b>Before we go any further we need to complete some unfinished business from the last article. After adding the FrameworkTimer class we were no longer able to build the project because we were missing the references to DirectX. Let's fix that now and
 add them. </p>
<ul>
<li>Right-click References in the Solution Explorer and select Add Reference. </li><li>On the .NET tab scroll down until you find the component named Microsoft.DirectX
</li><li>While pressing the CTRL key select the following components: Microsoft.DirectX, Microsoft.DirectX.Direct3D and click OK.
</li><li>The last step we need to complete before we can finally build the solution is to comment out the portions of the dxmutmisc.cs file we do not need.
</li><li>Open the dxmutmisc.cs file and comment out all of the code other than that in the Native Methods and Timer regions.
</li><li>Now build the solution (press F6). If you did everything right the solution will now build.
</li></ul>
<h4>&nbsp;My GPU is Bigger than Yours</h4>
<p>Before we dig into the DirectX API let's take a step back and think about what we are trying to do. To create a fast game we need to use some type of processor that allows us to compute the actual picture that will be shown on the monitor. Since none of
 us have 3D monitors that image will be 2D. So we need to do some math to compute each and every frame by converting 3D models into 2D images. If we used the CPU of the computer for all of these calculations our game would run slower, since we also have to
 use the same CPU to compute the AI, check for input, and oh by the way, we still need to run the operating system and all the background processes. If we can pass the computation of the graphics portions to a separate processor we can speed things up.
</p>
<p>Modern graphics cards have their own processor called a Graphics Processing Unit or GPU. These GPUs are specialized processors optimized to do the type of calculations we need. In addition each graphics card also has its own memory, in effect making it a
 separate computer inside our computer. This means that regardless how big and fast your basic computer is, graphics speed is dependent more on the GPU and video memory than anything else.
</p>
<h4>Adapters and Devices</h4>
<p>Most graphics cards allow only one monitor to be connected at a time, but some provide support for multiple monitors. You could also have more than one graphics card in your computer at a time. Regardless of your setup, each graphics card has an
<b>Adapter</b>. You can think of this as the physical video card in your computer.&nbsp; The adapters have “names” in the computer sense, with the first, or default adapter, being “named” 0, the second adapter 1 and so on. In DirectX you do not directly interact
 with the adapter. Instead you connect to an adapter using a <b>Device</b>. </p>
<p>A device represents a connection to a specific adapter; each adapter can have multiple devices associated with it. DirectX supports three types of devices: Hardware, References and Software. We will use the Hardware type for our game as it provides the speed
 we need to run our game. </p>
<p>Now its time to create the device we are going to use for our game. Add the following code to the constructor of the GameEngine form after the existing code. We are using the constructor because we can guarantee that any code in it will be run before anything
 else. This ensures that we always have a valid device object to reference later on.
</p>
<ul>
<li>Add the following code to the GameEngine constructor immediately following the this.SetStyle statement
</li></ul>
<p><b>Visual C#</b></p>
<pre class="csharpcode"><span class="rem">// Get the ordinal for  the default adapter    </span><br><span class="kwrd">int</span> adapterOrdinal =  Manager.Adapters.Default.Adapter;     <br><span class="rem">// Get our device capabilities so  we can check them to set up the      </span><br><span class="rem">// CreateFlags    </span><br>Caps caps = Manager.GetDeviceCaps(adapterOrdinal, DeviceType.Hardware);<br>CreateFlags createFlags;     <br><span class="rem">// Check the capabilities of the  graphcis card is capable of    </span><br><span class="rem">// performing the vertex-processing  operations    </span><br><span class="rem">// The HardwareVertexProcessing  choice is the best    </span><br><span class="kwrd">if</span>  (caps.DeviceCaps.SupportsHardwareTransformAndLight)    <br>{<br>    createFlags = CreateFlags.HardwareVertexProcessing;<br>}    <br><span class="kwrd">else</span><br>{<br>    createFlags = CreateFlags.SoftwareVertexProcessing;<br>}<br><span class="rem">// If the graphics card supports  vertex processing check if the device</span><br><span class="rem">// can do rasterization, matrix  transformations, and lighting and     </span><br><span class="rem">//shading operations    </span><br><span class="rem">// This combination provides the  fastest game experience    </span><br><span class="kwrd">if</span>  (caps.DeviceCaps.SupportsPureDevice &amp;&amp; createFlags ==  <br>    CreateFlags.HardwareVertexProcessing)<br>{<br>    createFlags |= CreateFlags.PureDevice;<br>}     <br><br><span class="rem">// Set up the PresentParameters  which determine how the device behaves    </span><br>PresentParameters presentParams = <span class="kwrd">new</span> PresentParameters();    <br>presentParams.SwapEffect = SwapEffect.Discard;<br><br><span class="rem">// Make sure we are in windowed  mode when we are debugging    </span><br><span class="preproc">#if</span> DEBUG       <br>     presentParams.Windowed = <span class="kwrd">true</span>;<br><span class="preproc">#endif</span><br><span class="rem">// Now create the device    </span><br>device = <span class="kwrd">new</span>  Device(adapterOrdinal,DeviceType.Hardware,<span class="kwrd">this</span>, <br>     createFlags,presentParams);</pre>
<p><b>Visual Basic</b></p>
<pre class="csharpcode"><span class="rem">' Get the ordinal for the  default adapter</span><br><span class="kwrd">Dim</span> adapterOrdinal <span class="kwrd">As</span> <span class="kwrd">Integer</span> = Manager.Adapters.<span class="kwrd">Default</span>.Adapter<br><span class="rem">' Get our device capabilities so we  can check them to set up the</span><br> <span class="rem">' CreateFlags    </span><br><span class="kwrd">Dim</span> caps <span class="kwrd">As</span> Caps =  Manager.GetDeviceCaps(adapterOrdinal,<br>    DeviceType.Hardware)    <br><span class="kwrd">Dim</span> createFlags <span class="kwrd">As</span> CreateFlags       <br><br> <span class="rem">' Check the capabilities of the  graphcis card is capable of   </span><br> <span class="rem">' performing the vertex-processing  operations   </span><br> <span class="rem">' The HardwareVertexProcessing  choice is the best    </span><br><span class="kwrd">If</span>  caps.DeviceCaps.SupportsHardwareTransformAndLight <span class="kwrd">Then</span><br>    createFlags = createFlags.HardwareVertexProcessing    <br><span class="kwrd">Else</span><br>    createFlags = createFlags.SoftwareVertexProcessing<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="rem">' If the graphics card supports  vertex processing check if the device</span><br><span class="rem">' can    </span><br><span class="rem">' do rasterization, matrix  transformations, and lighting and shading</span><br> <span class="rem">' operations   </span><br> <span class="rem">' This combination provides the  fastest game experience   </span><br><span class="kwrd">If</span>  caps.DeviceCaps.SupportsPureDevice <span class="kwrd">AndAlso</span> createFlags = _<br>        createFlags.HardwareVertexProcessing <span class="kwrd">Then</span><br>    createFlags = createFlags <span class="kwrd">Or</span> createFlags.PureDevice<br><span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="rem">' Set up the PresentParameters  which determine how the device behaves</span><br><span class="kwrd">Dim</span> presentParams <span class="kwrd">As</span> <span class="kwrd">New</span> PresentParameters()<br>presentParams.SwapEffect = SwapEffect.Discard<br><br><span class="rem">' Make sure we are in windowed mode  when we are debugging</span><br><span class="preproc">#If</span> DEBUG <span class="kwrd">Then</span><br>    presentParams.Windowed = <span class="kwrd">True</span><br><span class="preproc">#End If</span><br><span class="rem">' Now create the device</span><br>device = <span class="kwrd">New</span>  Device(adapterOrdinal, DeviceType.Hardware, <span class="kwrd">Me</span>, _<br>    createFlags, presentParams)<br></pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<ul>
<li>At the end of the form, right after the declaration of the deltaTime variable, add the following code:
</li></ul>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> Device device;</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> device <span class="kwrd">As</span> Device</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This is a lot of code just to get a Device configured, but this approach to setting up the device is the safest way of ensuring that we maximize the performance of our game based on the graphics card's hardware. The easiest way to understand this block of
 code is to break it into four distinct pieces. </p>
<ol>
<li>The first line of code simply gets the name of the default adapter which is usually 0. Instead of betting that it is zero it is safer to use the Manager class to get the name of the default adapter. This way things don't go south if for some reason the
 default adapter name is really 2. </li><li>The next section of code is used to determine the settings of the CreateFlags enumeration that we pass to the Device constructor and which governs the behavior of the device after creation. Again we use the Manager to get a listing of the capabilities (called
 Caps for short) for the default adapter. We then use this listing of capabilities to determine whether to perform vertex processing in hardware (which is faster) or in software (which is slower but guaranteed to always work). This is actually a misnomer, as
 the SoftwareVertexProcessing really means that we use the CPU while the HardwareVertexProcessing uses the GPU. We then perform another check to see if our adapter can support a pure device, meaning the graphics card can do rasterization, matrix transformations
 and lighting and shading calculations. If the device can and the previous check determined that we can use hardware vertex processing we add the PureDevice setting to the CreateFlags enumeration. The combination of HardwareVertexProcessing and PureDevice provides
 us with the best possible performance, so we want to use it if we can. </li><li>The final parameter required to create the Device is the PresentParameters object. This object determines how the device presents its data to the screen, hence the name. First we set the SwapEffect enumeration, which determines how the buffer and the device
 relate to each other. By selecting the Discard option we are choosing to simply discard the back buffer and write directly to the front buffer. Inside the If statement we determine if the application is running in Debug mode. If we are in debug mode we do
 not want to run in full screen mode, which is the default, because it makes debugging very difficult. Using this method to determine the configuration is better than hard coding it and then forgetting to switch it when releasing the game.
</li><li>The final step is to actually create the device. We pass in the ordinal of the default adapter, the window we want to bind the device to, the device type, and then pass in the CreateFlags and PresentParameters objects we created previously.
</li></ol>
<p>The net effect of all of this code is that we have a valid device we can use to draw to the screen with. To actually use the device we need to add two lines of code inside the render loop.
</p>
<ul>
<li>Add the following code in the OnPaint method immediately following the FrameworkTimer.Start() statement.
</li></ul>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Clear(ClearFlags.Target, Color.DarkBlue, 1.0f, 0);<br>device.Present();</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">device.Clear(ClearFlags.Target, Color.DarkBlue, 1.0F, 0)<br>device.Present()</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The first line clears the window with the color indicated in the second parameter (you can use any of the predefined windows colors in the Color enumeration). The last two parameters of the Clear method describe the z-depth and stencil values and are not
 important at this time. </p>
<p>The Present method of the device causes the device to display the contents of the back buffer to the screen. The screen is also called the front buffer and how these buffers interact is the determined by the SwapEffect enumeration you set earlier.
</p>
<p>Now we run the solution and viola – we have a blue screen. While this is not very impressive and it seems like a lot of code to get a simple blue screen we have now successfully integrated DirectX into our GameEngine.
</p>
<h4>3D Graphics Terminology</h4>
<p>Before we continue and render the terrain and units we need to step back for a minute and cover some of the principles and definitions used in three-dimensional graphics programming. We are not doing this so we can sound smart among our friends, but because
 these principles and terms provide the foundation for programming with three-dimensional graphics.
</p>
<p>The game I am currently playing is called Brothers in Arms: Road to Hill 30 (www.brothersinarmsgame.com). It is a first person shooter game set in Normandy France in 1942. All of the terrain, buildings, roads, rivers, etc. in this game are exact replicas
 of the original terrain in Normandy in 1942. The game creators used aerial photographs and maps to recreate the terrain and traveled to France to survey the terrain themselves. They used this information to recreate the original terrain for the game. When
 we need to describe where in the world something is located, such as the Space Needle in Seattle, we commonly use a coordinate system called the geographic coordinate system (<a href="http://en.wikipedia.org/wiki/Geographic_coordinate_system">http://en.wikipedia.org/wiki/Geographic_coordinate_system</a>).
 In this system we express each point as a unique Latitude/Longitude pair (the Space Needle is located at: Lat: 47.62117, Long: -122.34923).
</p>
<p>When the creators of the game transferred the terrain to the computer they could not just provide the Latitude/Longitude coordinates to DirectX because the computer has no idea how to represent geographic coordinates. To be able to place objects into a three-dimensional
 world we have to come up with a coordinate system the computer does understand and transform the coordinates from one system to another. The coordinate system used in DirectX is the left-handed Cartesian coordinate system.
</p>
<h5>Cartesian Coordinate system</h5>
<p>To properly place objects into a three-dimensional world we need to know where to place them and how to define each point unambiguously. We accomplish this using the Cartesian coordinate system. This Cartesian coordinate system is comprised of three axes
 at right angles to each other with the point of intersection being called the <b>
origin </b>(the one you are probably more familiar with is the two-dimensional version with only the x and y axes used in High School geometry). Two additional properties are needed to fully define this three-dimensional coordinate system: handedness and orientation.
</p>
<h5>Handedness</h5>
<p>To make life just a little bit more challenging, there are actually two ways to represent a three-dimensional Cartesian coordinate system: Left-handed and right-handed. If you follow this link (<a href="http://en.wikipedia.org/wiki/Cartesian_coordinate_system">http://en.wikipedia.org/wiki/Cartesian_coordinate_system</a>)
 you can find out more behind the reason for this, but the main thing to remember is that DirectX uses the left-handed coordinate system. The net effect of using the left-handed coordinate system is that the greater the Z value the greater the distance, while
 in the right-handed system the values get smaller as the distance increases. You need to know the handedness of the coordinate space to compare two objects using their Z values and to know which one is further away from you.
</p>
<h5>Orientation</h5>
<p>The only other thing of note about the three-dimensional Cartesian coordinate system is that it can have different orientations depending on how the z-axis is drawn. If it is drawn vertically as pictured below on the left then it is called the world coordinates
 orientation if it is drawn as on the right it is called the local or body coordinates orientation.
</p>
<p>Regardless of the orientation you use to reference your points to, the coordinates must be transformed to screen coordinates (two-dimensional screen space) in order to be drawn on the screen.
</p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/940223/image001.jpg">
</p>
<p><b>Figure 2: 3D Cartesian Coordinate systems</b> </p>
<h5>Vector</h5>
<p>Each point in the three-dimensional coordinate system is defined by three values, the X, Y and Z values. To make life a little easier DirectX provides us with a structure called a Vector3 that lets us store these coordinates. This is purely for our convenience
 though, as a vector is defined as an object that denotes both direction and velocity and not a location. The methods of the vector class are used towards that end, but for now it's a convenient structure to store the three values in. Depending on your need
 can also use the Vector2 or Vector4 structures. </p>
<h5>Vertex</h5>
<p>In the code we added to connect to our device you may have noticed that we needed to determine if we should do vertex processing in software or hardware. So what is vertex processing and what is a vertex? A vertex is a point that is part of a three-dimensional
 object. A vertex consists of a vector and additional information concerning texture mapping.
</p>
<h5>Texture</h5>
<p>A texture is simply a 2D bitmap that is applied to a 3D object to provide it with some type of look (texture) such as grass, concrete etc.
</p>
<h5>Mesh</h5>
<p>We are not going to cover using meshes in this article; the definition of a mesh is tied to that of a vertex, so let's get it out of the way now. A mesh is the data that describes a three-dimensional shape. This data includes the list of vertexes for the
 shape as well as information describing how the vertexes are connected and information concerning the textures that cover them.
</p>
<p>As you can see, a Mesh is made up of vertices, which in turn contain a vector. Each level simply adds some information concerning how the separate pieces are related to each other. From now on when you hear vector think point, when you hear vertex think
 point and data, and when you hear mesh think many points and more data. </p>
<h5>Triangles</h5>
<p>Now that you know that a vertex is really just a point in 3D space, we need to cover how the points are combined to form the objects. Every object in DirectX is composed of one or more triangles. While this may seem awkward at first, it is actually possible
 to represent any 2D or 3D shape using triangles. The reason for this is simple: triangles are the simplest polygon that is coplanar (all the points of the triangle are on the same plane). This simplifies the math needed to perform all calculations.
</p>
<p>While all of this seems to be a lot of new terms to learn, it is important to understand these basic ideas before moving on to matrices. We are going to cover them and the principle behind a camera (in the DirectX sense of the word) and transformations in
 the next article. We are also going to explain what meshes are and how the texture mapping information of a vertex is used.
</p>
<h5>A Frame Rate Counter</h5>
<p><b></b>As I mentioned in the first article, we are going to add a frame rate counter to our game. Knowing the frame rate of your game is important because it determines the speed of your game. Additionally, knowing what the frame rate is now before we add
 any code to the render loop will show us how each addition affects the speed of the game.
</p>
<ul>
<li>Add a new class to the project and name it FrameRate. </li><li>Add the following code inside the class declaration. </li></ul>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">int</span> CalculateFrameRate()<br>{<br>    <span class="kwrd">if</span>  (System.Environment.TickCount - lastTick &gt;= 1000)<br>    {<br>        lastFrameRate = frameRate;<br>        frameRate = 0;<br>        lastTick = System.Environment.TickCount;<br>    }<br>    frameRate&#43;&#43;;<br>    <span class="kwrd">return</span> lastFrameRate;<br>}<br><br><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">int</span> lastTick;<br><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">int</span> lastFrameRate;<br><span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">int</span> frameRate;</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> CalculateFrameRate() <span class="kwrd">As</span> <span class="kwrd">Integer</span><br>    <span class="kwrd">If</span>  System.Environment.TickCount - lastTick &gt;= 1000 <span class="kwrd">Then</span><br>        lastFrameRate = frameRate<br>        frameRate = 0<br>        lastTick = System.Environment.TickCount<br>    <span class="kwrd">End</span> <span class="kwrd">If</span>     frameRate &#43;= 1<br>    <span class="kwrd">Return</span> lastFrameRate<br><span class="kwrd">End</span> <span class="kwrd">Function</span> <span class="rem">'CalculateFrameRate</span> <br><br><span class="kwrd">Private</span> <span class="kwrd">Shared</span> lastTick <span class="kwrd">As</span> <span class="kwrd">Integer</span><br><span class="kwrd">Private</span> <span class="kwrd">Shared</span> lastFrameRate <span class="kwrd">As</span> <span class="kwrd">Integer</span><br><span class="kwrd">Private</span> <span class="kwrd">Shared</span> frameRate <span class="kwrd">As</span> Integer</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<ul>
<li>In the GameEngine OnPaint method add the following line of code immediately after the assignment of deltaTime.
</li></ul>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">this</span>.Text = <span class="kwrd">string</span>.Format(<span class="str">&quot;The framerate is {0}&quot;</span>, <br>    FrameRate.CalculateFrameRate());</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"></pre>
<pre class="csharpcode"><span class="kwrd">Me</span>.Text = <span class="kwrd">String</span>.Format(<span class="str">&quot;The framerate is {0}&quot;</span>, _<br>    FrameRate.CalculateFrameRate())</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This frame rate counter uses the TickCount property of the System class which is a wrapper to the GetTickCount method of the WIN32 API and has a precision of approximately 15 milliseconds. While the FrameworkTimer class is more accurate, this precision is
 good enough to compute the frame rate. </p>
<h4>Code Housekeeping</h4>
<p><b></b>Before we finish up there are two code changes I made to the original code. First I removed the Application.EnablRTLMirroring() statement from the Program class. This method has been deprecated in the Beta2 version of the .NET Framework. The other
 change I made is to wrap the creation of the GameEngine class into a using statement. This ensures that regardless of what happens in the GameEngine class it will always be properly disposed when we close the application.
</p>
<h4>Summary</h4>
<p><b></b>At this point you might be wondering if we are ever going to start working on our game. One of the challenges with learning game development is that you have to create a good foundation at the beginning so the more advanced ideas make sense later
 on. Once you understand the 3D graphics terms and principles you are free to concentrate on the game creation.
</p>
<p>In this article we introduced DirectX which is the API we are going to use for 3D graphics, input device control and sound in BattleTank 2005. Then we discussed what a GPU is and why it is so important for today's games. We also covered what an Adapter and
 Device are and how to configure them in DirectX. Then we entered the world of terms and definitions that we need to understand moving forward. Finally we added a frame rate counter to the game to track game performance.
</p>
<p>In the next article we'll cover matrices and transforms, how to place a camera into the 3D world and what clipping and culling are. In that article we are also going to add the landscape for our game.
</p>
<p>I hope that the first foray into the world of DirectX has not discouraged you too much. Because some definitions and principles are a little hard to understand just by reading them I suggest you write some code and play with the various settings to see what
 happens. The DirectX SDK also includes a great number of samples and tutorials that cover this same subject matter and let you experiment with the settings.</p>
<span>]]&gt;</span> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:63be0b27bea14c27be799e7600d98732">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-II-Introduction-to-DirectX</comments>
      <itunes:summary>



&amp;nbsp;
This is Part 2 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. This article covers the basics of DirectX.



Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions,
DirectX SDK
Hardware: None
Download: Download

&amp;nbsp;
Beginning Game Development Series


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III








Introduction
Welcome to the second article on beginning game development. In this article we are going to cover the basics of DirectX.
 
DirectX is a multimedia API that provides a standard interface to interact with graphics and sound cards, input devices and more. Without this standard set of APIs you would have to write different code for each combination of graphics and sound cards and
 for each type of keyboard, mouse and joystick. DirectX abstracts us from the specific hardware and translates a common set of instructions into the hardware specific commands.
 
Like all new tools, DirectX has a number of new terms and definitions that you need to understand. In addition to these new terms you also are going to have to brush up on your math skills. DirectX and game development in general is pretty math intensive,
 and it helps if you understand the basics. There is no need to get out the old calculator however, the idea is to understand the goal and the way to get to that goal, the </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-II-Introduction-to-DirectX</link>
      <pubDate>Fri, 03 Nov 2006 05:56:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-II-Introduction-to-DirectX</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/940223_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/940223_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>17</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-II-Introduction-to-DirectX/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Beginning Game Development: Part I – Introduction</title>
      <description><![CDATA[
<table cellpadding="1" cellspacing="0" border="0">
<tbody>
<tr class="entry_overview">
<td width="50">&nbsp;</td>
<td>
<p><span class="entry_description">This is Part 1 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0.</span></p>
<p><span class="entry_description"><strong>WARNING: </strong>Managed DirectX is no longer supported.&nbsp; If you want to do 3D graphics with the .NET Framework, please use XNA (<a href="http://creators.xna.com/">http://creators.xna.com</a>)</span></p>
</td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author">Derek Pierson</div>
<div class="entry_company"><a href="http://www.3leafdev.com/Home.aspx">3Leaf Development</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Basic or Visual C# Express Editions</a>,
<a href="http://www.microsoft.com/windows/directx/default.mspx">DirectX SDK</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input">None</span></div>
<div class="entry_details">&nbsp;</div>
<div class="entry_details"><strong>Beginning Game Development Series</strong></div>
<ol>
<li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/02/938703.aspx">Beginning Game Development Part 1 - Introduction</a></div>
</li><li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940223.aspx">Beginning Game Development Part II - Introduction to DirectX</a></div>
</li><li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx" title="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940729.aspx">Beginning Game Development: Part III - DirectX II</a></div>
</li><li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/940908.aspx">Beginning Game Development: Part IV - DirectInput</a></div>
</li><li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/03/941679.aspx">Beginning Game Development: Part V - Adding Units</a>
</div>
</li><li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044115.aspx">Beginning Game Development: Part VI - Lights, Materials and Terrain</a></div>
</li><li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/09/1044454.aspx">Beginning Game Development: Part VII –Terrain and Collision Detection</a></div>
</li><li>
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2006/11/06/999786.aspx">Beginning Game Development: Part VIII - DirectSound</a></div>
</li><li>
<div class="entry_details">
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2007/11/02/5849691.aspx">Beginning Game Development: Part VIII - DirectSound II</a></div>
</div>
</li><li>
<div class="entry_details">
<div class="entry_details">
<div class="entry_details"><a href="http://blogs.msdn.com/coding4fun/archive/2008/01/07/7020067.aspx">Beginning Game Development: Part VIII - DirectSound III</a></div>
</div>
</div>
</li></ol>
</td>
</tr>
</tbody>
</table>
<p><b>Part I – Introduction</b> </p>
<p>Welcome to the first article of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0.
</p>
<p>This series as aimed at beginning programmers who are interested in developing a game for their own use with the .NET Framework and DirectX. The goal of this series is to have fun creating a game and learn game development and DirectX along the way. Game
 programming and DirectX have their own terms and definitions that can be difficult to understand, but after awhile, you’ll crack the code and be able to explore a new world of possibilities. I will keep things as straightforward as possible and decode terms
 as they appear. Another part of the learning curve comes from the math you’ll need to deal with DirectX. I am going to point out some resources along the way that will help you brush up on, or learn, the math skills you’ll need to keep going in DirectX.
</p>
<p>In this series, we are going to build a simple game to illustrate the various components of a commercial game. We will cover how to create great looking graphics in 3D, how to handle user input, how to add sound to a game, how to create computer opponents
 using Artificial Intelligence, and how to model real-world physics. In addition we are going to cover how to make your game playable over the network and how to optimize your game for performance. Along the way, I will show you how to apply principles of object-oriented
 development and, as well, I will share some of my experience in creating well-organized and elegant code.
</p>
<h4>Tools:</h4>
<p>Before we start writing our first game we need to talk about the tools we will use.
</p>
<p>The most important tool for any developer is the Integrated Development Environment (IDE). This is where you are going to spend the majority of your time writing and debugging code, so it needs be powerful and fast.
</p>
<p>Visual Studio 2005 (also known by the codename “Whidbey&quot;) is the third version of the standard Microsoft IDE for .NET Framework-based applications. Visual Studio 2005 introduces a number of Express versions that provide most of the functionality of their
 more advanced counterparts but are simplified for the novice, hobbyist, and student developer and cost much less (There are express versions available for VB, C#, C&#43;&#43;, J# and for Web Developers using ASP.NET). For this series, I am going to use both Visual
 C# Express and Visual Basic Express. If you have not already done so, download the C# or Visual Basic Visual Studio Express IDE at:
<a href="http://msdn.microsoft.com/express">http://msdn.microsoft.com/express</a>.
</p>
<p>The second important tool we need to create a great looking game is a graphics Application Programming Interface (API). Without such an API it would be extremely difficult to access the graphics capabilities of your PC. The API we are going use is the DirectX
 API. This API allows us to create powerful multimedia applications on the Windows platform. To work on the game, you will need to download the latest DirectX SDK at:
<a href="http://www.microsoft.com/windows/directx/default.aspx">http://www.microsoft.com/windows/directx/default.aspx</a>. Make sure that you download the SDK and not just the runtime. The SDK includes samples and other utilities that are extremely useful when
 developing using DirectX. </p>
<p>At some point in your game development experience you are going to have to create or modify graphics. Every copy of Microsoft Windows comes with Microsoft Paint, and while it is not the most powerful program, you already own it and it is good enough for
 most of our needs. </p>
<p>As we dive deeper into DirectX and cover 3D models and sounds, you might find the need to use other programs to manipulate the image or sound files. As we cover these topics I will point you towards free or inexpensive programs and resources on the Web.
</p>
<p>Finally, you need to know where to go to get help. One of the best places is &nbsp;the public newsgroups. Here, you can ask questions and get answers from people with the same interests as you. Microsoft MVPs and employees also monitor these newsgroups and provide
 help for you along the way. The newsgroups that are going to be of most interest for game programming are:
</p>
<ul>
<li>Managed DirectX: <a href="http://msdn.microsoft.com/newsgroups/default.aspx?dg=microsoft.public.win32.programmer.directx.managed&amp;lang=en&amp;cr=US">
microsoft.public.win32.programmer.directx.managed</a> </li><li>C#: <a href="http://msdn.microsoft.com/newsgroups/default.aspx?dg=microsoft.public.dotnet.languages.csharp&amp;lang=en&amp;cr=US">
microsoft.dotnet.languages.csharp</a> </li><li>VB: <a href="http://msdn.microsoft.com/newsgroups/default.aspx?dg=microsoft.public.dotnet.languages.vb&amp;lang=en&amp;cr=US">
microsoft.dotnet.languages.vb</a> </li></ul>
<p>Other places to go for inspiration and help for gaming are: </p>
<ul>
<li>The ZBuffer: <a href="http://www.thezbuffer.com/">http://www.thezbuffer.com/</a>
</li><li>GameDev.net: <a href="http://www.gamedev.net/">http://www.gamedev.net/</a> </li><li>flipCode: <a href="http://www.flipcode.com/">http://www.flipcode.com/</a> </li><li>Gamasutra: <a href="http://www.gamasutra.com/">http://www.gamasutra.com/</a> [Professional audience, but many articles from Game Developer, including tutorials]
</li></ul>
<h4>&nbsp;What makes a successful game?</h4>
<p>My first experience using a computer was in 1981 on a Sinclair ZX Spectrum. The first 5 years of my computing life were spent on nothing but writing and modifying games for the Sinclair and later the Commodore 64, but, heck, what else are you going to do
 as a teenager? While much has changed in terms of hardware capabilities and available APIs, the properties of a great game have not.
</p>
<p>Games today have become so complex that they require large numbers of developers, graphic artists, testers and managerial overhead to develop. They rival large commercial enterprise application in their complexity and cost many millions of dollars to develop
 and market. The payback, however, can be enormous and rival Hollywood blockbuster movies in sales – Halo 2 grossed $100M in its first day of availability. &nbsp;
</p>
<p>All successful games have a couple of features in common that made them stand out.
</p>
<ul>
<li>The main ingredient for a successful game is the game idea. Regardless how cool your graphics are, how good the music is, if the idea is lame no one is going to play the game.
</li><li>The second most important feature is the playability of the game. If the game is too hard then players are quickly going to get frustrated and stop playing. Conversely, if the game play is too easy then the player is going to get bored and stop playing.
 A good game provides multiple levels of difficulty that continuously challenge the player without overwhelming or boring them.
</li><li>Together, the game idea and its playability are the “game design” (not to be confused with “level design,” which is the application of the overall game design to specific segments of the game). There are certain game designers who have a golden touch. Shigeru
 Miyamoto (the creator of Donkey Kong, Zelda, and Mario) and Will Wright (Sim-everything) are two prominent examples. Miyamoto’s keynote address to the 1999 Game Developer’s Conference is available at
<a href="http://www.gamasutra.com/features/20030502/miyamoto_01.shtml">http://www.gamasutra.com/features/20030502/miyamoto_01.shtml</a> and Wright’s recent discussion of the design philosophy of Spore (<a href="http://www.gamespy.com/articles/595/595975p1.html?fromint=1">http://www.gamespy.com/articles/595/595975p1.html?fromint=1</a>)
 are good inspirations for designers of all stripes, while the book “Theory of Fun for Game Design” by Raph Koster has gotten excellent reviews in the community.
</li><li>The third ingredient to a successful game is the set of graphics. They need to be good enough to compliment the game idea and game play but not so resource intensive or flashy that they distract from it.
</li><li>The final ingredient is performance. No one wants to play a slow game. I still remember an adventure game on my Commodore64 that took 10 minutes to render each scene. I still played it, mind you, because the game idea was great and there were no other options
 around but it was irritating.&nbsp; Graphics and performance are closely related. The more fancy graphics you add to a game to slower the performance. The next biggest performance issue is the AI. A lot of game development today focuses on how to make things faster
 and not coming up with new ideas. However, when you’re learning a complex programming technique such as game programming, it’s vitally important not to optimize prematurely. An understanding of the performance pipelines, and the
<i>skills</i> to write clean code, profile it, and improve it are much more important than any single optimized function.&nbsp;&nbsp;
</li></ul>
<p>If you apply your design efforts in this order you, too, can create a great game. It may not be a refined first person shooter like Battlefield 1942, but Tetris is arguably one of the most popular games and has neither fancy 3D graphics nor Dolby digital
 sound. Even today, games like Gish (<a href="http://www.chroniclogic.com/index.htm?gish.htm">http://www.chroniclogic.com/index.htm?gish.htm</a>) demonstrate what can come from creative independent developers. If you can write enough of a game to show your
 game idea, then maybe you can interest the large gaming companies in your game. The Independent Games Festival is the “Sundance” of the game community, runs concurrently with the professional Game Developers Conference and, believe me, is among the most closely-watched
 events at the show. </p>
<h4>Our Game idea:&nbsp;</h4>
<p>Now that you know what features make a great game, the next step is to lay out the game proposal for our game.
</p>
<p><span>Idea</span>: Since coming up with a unique and creative game idea is the core of any game, I am going to cheat and use the game idea from the first 3D game I ever saw: Atari’s Battlezone. (If I had that great idea why would I let of all you know anyway?)
 Battlezone is a basic first-person shooter game in which you are looking through the viewfinder of a tank into a 3D landscape. The goal is to destroy as many of the opponent’s tanks as possible before getting destroyed yourself. The landscape includes random
 objects behind which you can hide. The game screen includes a radar to show you the location of your opponents and the current score.
</p>
<p><span>Playability</span>: The original game started out fairly slowly but kept adding more opponent tanks and other random enemies.&nbsp; The game also increased the speed and intelligence of the opponents. All of this kept the game challenging but playable.
</p>
<p><span>Graphics</span>: The original game used graphics that proved just engaging enough to feel like you were in a 3D world, but because of the hardware available in 1980 (an 8-bit processor running at 1.5
<i>mega</i>hertz) it rendered the 3D objects as wire frames. These graphics were advanced when the game first came out, but we are going to improve upon them using the magic of DirectX (and the magic of 25 years of Moore’s Law!).
</p>
<p><b>Screenshot of Atari’s Battlezone game – complete with wire frame mountains, tanks, and even a wire frame moon for added realism!</b>
</p>
<p><span>Performance</span>: This game pushed the limits of the hardware available at the time. This is evident in the use of the wire frame objects. If the game had been written to fill these objects then it would have been unplayable. With today’s advanced
 hardware we should not have any performance issues other than those introduced by us writing sloppy code.
</p>
<p>Now that we have decided on a game, the next step is to write down the goals of your game. This does not need to be anything formal but the simple act of writing things down has the tendency to make ideas clearer. At a minimum you need to determine the object
 of the game, what the player can and cannot do and how the player interacts with the game. We also should define what the scoring system is going to be like and what are the victory conditions.
</p>
<p>For our game these are the simple specification I came up with. </p>
<ul>
<li>A 3D first-person shooter game </li><li>The goal is to destroy as many enemies as possible </li><li>The player can move through the landscape on the ground just as a regular tank can. The tank can not fly, nor can it change speed.
</li><li>The game play will be controlled through the keyboard for moving and shooting. The mouse will be used to interact with the menus and start/stop the game. We will not support a joystick.
</li><li>The player will receive a score that is based on the distance at which the enemy tank was destroyed. The further the tank was, the higher the score. Each round fired reduces the score by a set amount, unless that round hits a target.
</li><li>The game will be divided into levels. Each level will have a pre-defined number of enemies. Once all enemies have been eliminated, the player advances to the next level. There is no limit to the levels.
</li></ul>
<p>Now we are ready to do some coding. In general, it is best to write down just the overall idea of the application. Spending a lot of effort upfront designing every little detail is just a waste of time. As we add more functionally to the game we will continuously
 do small design sessions to formulate our ideas. This iterative approach to developing software is the best way to create good software, and is more fun at the same time.
</p>
<h4>Creating the game Project:</h4>
<p>Now we are ready to write some code. The first step is to create a new solution in Visual Studio 2005.
</p>
<ul>
<li>Select <b>File | New | Project</b> and choose <b>Windows Application</b> from the template list. In the Name field at the bottom of the dialog, replace the default
<b>WindowsApplication1</b> with <b>BattleTank2005</b> and click <b>OK</b>. </li></ul>
<p>Visual Studio now creates a new solution for us called BattleTank2005 that contains a single project with the same name.
</p>
<p>First, we need to rename the class to something more descriptive. Naming is one of the most efficient methods of keeping code well organized and understandable. Always choose names that clearly describe what the item is doing and avoid meaningless names
 like Class1 and Form1. </p>
<ul>
<li>From the Edit menu, select Find and Replace, then select Quick Replace. Set the
<b>Find What</b> field to 'Form1', <b>Replace What</b> field to 'GameEngine' and the
<b>Look in</b> field to 'Current Project' (see Figure below). Click Replace All to make this change (there should be five changes made)
</li><li>Next <b>right-click</b> <b>Form1</b> in the <b>Solution Explorer</b> and select
<b>Rename</b>. Change Form1.cs to GameEngine.cs. </li></ul>
<p><b>Replacing Form1 text with GameEngine. You'll thank yourself later.</b> </p>
<p>Another trick to keeping things organized is to ensure that the files in the Solution Explorer are named exactly the same as the classes they contain and to always create a separate file for each distinct element such as each class or enumeration.
</p>
<p>Now we have a Windows application that we can run, but it doesn’t do anything. The form has no other controls on it such as buttons you can click or textboxes to display any information. In a regular Windows Forms application we would now add such controls
 to the forms to create our final application, but for our game we are going draw everything using the DirectX API rather than the Windows Forms API.
</p>
<p>We really only need the Form for its Windows Handle, which is basically its unique name among all the other windows on the screen. We will use this handle to set up our DirectX drawing surface. The other use of the Form is that it contains an event that
 we are going to use to create our render loop. </p>
<h4>Adding the Render loop</h4>
<p>A game is much different from a regular application, such as Microsoft Word. Word presents a screen to the user that mimics a page in a typewriter and then waits for the user to do something. This something could be pressing the keys on the keyboard or selecting
 a menu item from the menu with the mouse. While waiting for the user to interact with the application Word does nothing. (Actually I lie: it
<i>does</i> do things like run spell checking and auto save in the background but nothing you as the user can see). Generally, programs written using the Windows Forms library generally have the same behavior – they don’t consume CPU time unless the user is
 doing something (of course, it’s possible to use the Timer control or the capabilities of the System.Threading namespace to do things independent of the user).
</p>
<p>Games are different. As you know, smooth movement in games requires the screen to be updated many times per second. The “flicker fusion threshold” at which static images begin to fuse is generally taken to be 1/16 of a second, although it actually varies
 depending on illumination (brighter lights like computer monitors require higher frame rates) and where on the retina the image falls (peripheral vision requires higher rates than foveal vision). Although movies are shown at 24 frames per second (FPS), 30
 FPS is often considered the lowest-acceptable rate for video games, and most actiongame players tune their graphics for no less than 60 FPS.
</p>
<p>Because the render loop is called dozens of times per second and runs nonstop, game programming almost always uses the render loop as the “stopwatch” of the game, calculating everything inside the loop, not just graphics, but physics, AI, checking for user
 input, and scores. (Again, you <i>could</i> use the Timer class or threads to write a multithreaded game, but doing so would introduce significant complexity without any clear benefits and although multithreading in the .NET Framework’s Common Language Runtime
 &nbsp;is quite efficient, the slight overhead could knock a couple frames per second off your game.)
</p>
<p>So how do we get the computer to run this loop? The form we added earlier has an event called the
<i>Paint</i> event. The <i>Paint</i> event for a Windows Form object is called whenever the form is redrawn. This normally occurs only when you maximize a form or when a form is covered by another form that is moved.
</p>
<p>As all Windows Forms programming, even game programming, is event-based, understanding the principles of events and event handlers is critical. Although the event is triggered automatically, we need to create a special method called an event handler to be
 able to intercept the event and do something in response to it.. </p>
<ul>
<li>In the GameEngine class add the following code after the constructor. </li></ul>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPaint(PaintEventArgs e)<br>{<br>          <br>}</pre>
<p><style type="text/css">
   </style></p>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Protected</span> <span class="kwrd">Overrides</span> <span class="kwrd">Sub</span> OnPaint(<span class="kwrd">ByVal</span> e <span class="kwrd">As</span> PaintEventArgs)<br>          <br><span class="kwrd">End</span> Sub</pre>
<p><style type="text/css">
   </style></p>
<p>This is our event handler. When is it called? “OnPaint” – when the Paint event occurs. One thing is still missing. Even though Windows and the Windows Forms library automatically raise the event, some actions that we might expect to trigger the Paint event
 don’t. Minimizing a window, for example, does not trigger the Paint event, since Windows does not see the need to repaint the entire form (Windows is just being efficient since we are actually displaying less when we are shrinking the form). So we cannot rely
 on these automatically-created events to manage the loop we need for our game. </p>
<p>Luckily, we can programmatically trigger the Paint event by calling the Invalidate method of a form. This causes the Paint event to be triggered and Windows to enter back into our OnPaint event handler. Then we execute any code we want to run every frame
 and start all over again by calling the Invalidate method. </p>
<p>You might ask, “Why can’t we just add a while(true) loop directly within OnPaint() and never leave it?” The answer is that even though we’re game programmers, we’re expected to play well with others. Creating a loop within OnPaint() would starve the rest
 of the programs running on the system. While our game might gain a few frames per second, the rest of the system would become, at best, ugly, and at worst, unstable. So, instead of directly looping, we essentially “ask” to be called again as soon as possible.
</p>
<ul>
<li>In the OnPaint method add the following line of code: </li></ul>
<p><b>Visual C#</b><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code></p>
<pre class="csharpcode"><span class="kwrd">this</span>.Invalidate();</pre>
<p><style type="text/css">
   </style></p>
<p><b>Visual Basic</b></p>
<pre class="csharpcode"><span class="kwrd">Me</span>.Invalidate()</pre>
<p><style type="text/css">
   </style></p>
<p>That’s it, we’ve created our render loop. But there is one more problem. It turns out that not
<i>all</i> painting is done in the OnPaint method, Windows Forms triggers another event when the background is erased and by default performs some painting (well, erasing) in response. To force our application to truly only paint inside our method handler,
 we need to add one more line of code to our application. Since we need to ensure that this code is run when the application starts, we place it into the constructor of the form. This means that we are guaranteed that this code is run before we call any methods
 on that class. </p>
<ul>
<li>In the GameEngine class add the following line of code to the constructor immediately following the InitializeComponent method call.
</li></ul>
<p><b>Visual C#</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">this</span>.SetStyle(ControlStyles.AllPaintingInWmPaint |<br>    ControlStyles.Opaque, <span class="kwrd">true</span>);</pre>
<p><style type="text/css">
   </style></p>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Me</span>.SetStyle(ControlStyles.AllPaintingInWmPaint <span class="kwrd">Or</span> <br>    ControlStyles.Opaque, <span class="kwrd">True</span>)</pre>
<p><style type="text/css">
   </style></p>
<p>Setting the ControlStyles to AllPaintingInWmPaint ensures that Windows only uses the OnPaint event handler to redraw the screen. The second parameter simply informs Windows that our window is not going to be transparent.
</p>
<p>Now we have the basic framework for our game. Everything we are going to create from now on out will be actions that occur inside the render loop.
</p>
<h4>Everything about timers</h4>
<p>One issue with this type of loop is that fact that the speed in which the computer can accomplish the tasks in the render loop varies from computer to computer. It even varies on the same computer according to how much memory and CPU time is available for
 the game at any given moment. We need to have some way of accounting for these differences to make sure that we animate consistently. So instead of treating each frame the same, we are going to calculate the time elapsed between frames and apply that value
 to our calculations. </p>
<p>There are a couple of different ways of keeping track of time in Windows: </p>
<ol>
<li><b>System.Windows.Forms.Timer</b>: This is the most common timer used in Windows programming. While it is easy to use, it only has a resolution of 1/18<sup>th</sup> of a second. Since we could have up to a thousand frames per second this resolution is not
 good enough for a game program. </li><li><b>timeGetTime</b>: This Windows DLL provides a resolution of 1 microsecond on some versions of Windows and 5 microseconds on Windows NT. This is too variable, and we really don’t want to check the operating system our game is running on to see if we need
 to adjust the timer values. </li><li><b>System.TickCount</b>: This managed call returns the number of ticks that indicate the number of milliseconds. This is close to what we want, but we can do better.
</li><li><b>QueryPerformanceCounter</b>: This is the preferred timer to use; it has a resolution of less than 1 microsecond. This is the timer most often used in game development.
</li></ol>
<p>The last timer is kind of tricky to write since it requires calls to a low-level DLL (kernel32 if you need to know) in Windows. Luckily for us the need for a high-resolution timer is universal and a timer class is included with the DirectX SDK. You can find
 the timer class in the \Samples\Managed\Common directory underneath the install directory of the SDK. The file we are interested in is called dxmutmisc.cs, but we will use most of the other files in that directory as we add more functionality to our own project.
</p>
<p>Before we add dxmutmisc.cs we are going to create a separate folder. Organizing a solution by folders makes it easy to group related items together and keeps the project more organized.
</p>
<ul>
<li>Selecting <b>Add | New Folder</b>. Name the new folder: <b>DirectXSupport</b>. This is where we are going to add the various support classes as we make use of them throughout this project.
</li></ul>
<p>Now we are going to add the existing file to our project. This copies the file to our directory structure.&nbsp;
</p>
<ul>
<li>Right-click the DirectXSupport folder and select Add | Add Existing Item and browse to C:\Program Files\Microsoft DirectX 9.0 SDK (February 2005)\Samples\Managed\Common and select the dxmutmisc.cs file.
</li></ul>
<p>If you want to, you can browse the contents of this file, it contains various other helper classes that save you from writing a lot of code yourself in addition to the FrameworkTimer class
</p>
<p>Since the timer class is contained in a different namespace we are going to add a
<code>using</code> statement so we can use the FrameworkTimer without having to write “Microsoft.Samples.DirectX.UtilityToolkit.FrameworkTimer” every time.
</p>
<ul>
<li>At the top of the class in the using directives region add the following line of code:
</li></ul>
<p><b>Visual C#</b></p>
<pre class="csharpcode">Microsoft.Samples.DirectX.UtilityToolkit;</pre>
<p><style type="text/css">
   </style></p>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode">Microsoft.Samples.DirectX.UtilityToolkit</pre>
<p><style type="text/css">
   </style></p>
<p>Next we need to have a way to store the value of the time elapsed. We are going to store this value in the deltaTime variable. Notice that we are declaring this variable as a double. If you declared it as an integer you would lose all of the resolution provided
 by our high-powered timer since everything would be rounded to an integer. </p>
<ul>
<li>At the end of the class above the last two braces add the following line of code.
</li></ul>
<p><b>Visual C#</b></p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">double</span> deltaTime;</pre>
<p><style type="text/css">
   </style></p>
<p><b>Visual Basic</b></p>
<pre class="csharpcode"><span class="kwrd">Private</span> deltaTime <span class="kwrd">As</span> Double</pre>
<p><style type="text/css">
   </style></p>
<p>We want to start the timer at the last possible moment in the render loop so we can get the most accurate time possible.
</p>
<ul>
<li>At the end of the OnPaint method right before the this.Invalidate call add the following code.
</li></ul>
<p><b>Visual C#</b><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code></p>
<pre class="csharpcode">FrameworkTimer.Start();</pre>
<p><style type="text/css">
   </style></p>
<p><b>Visual Basic</b></p>
<pre class="csharpcode">Microsoft.Samples.DirectX.UtilityToolkit.FrameworkTimer.Start()</pre>
<p><style type="text/css">
   </style></p>
<p>We need to calculate the elapsed (or delta) time at the start of each loop, because we are going to pass it to most of the subsequent calls we are going to make.
</p>
<ul>
<li>At the very top of the OnPaint method, before any other code, add the following line of code.
</li></ul>
<p><b>Visual C#</b></p>
<pre class="csharpcode">deltaTime = FrameworkTimer.GetElapsedTime();</pre>
<p><style type="text/css">
   </style></p>
<p><b>Visual Basic</b></p>
<pre class="csharpcode">deltaTime = Microsoft.Samples.DirectX.UtilityToolkit.FrameworkTimer.GetElapsedTime()</pre>
<p><style type="text/css">
   </style></p>
<p>That’s it. We now have a way to track time. As an added bonus, in the next article, we will use this timer to compute our frame rate. You will notice that the solution now will no longer build. This is because the classes in the file we added require DirectX
 to be referenced. We are going to cover which parts of DirectX we need in the next article.
</p>
<h4>Summary</h4>
<p>We have accomplished a lot in this first article. First, we covered the tools needed to created managed DirectX games and then we discussed the features that make a great game. Next, we defined our game idea and created our game project. After that, we created
 the render loop we are going to use throughout the game, and finally we added a high resolution timer to our project.&nbsp;
</p>
<p>The next steps all require DirectX, which we will cover in the next article. I hope that this initial article has motivated you to begin that game you always thought about. Game development can be one of the most satisfying experiences in computer programming,
 and as we progress through this series, I am going to teach you all the fundamentals you need to accomplish that goal.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Derek-Pierson/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:1d90c2033e04443faf539e7600d9942b">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-I--Introduction</comments>
      <itunes:summary>



&amp;nbsp;

This is Part 1 of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0. 
WARNING: Managed DirectX is no longer supported.&amp;nbsp; If you want to do 3D graphics with the .NET Framework, please use XNA (http://creators.xna.com) 




Derek Pierson
3Leaf Development

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions,
DirectX SDK
Hardware: None
&amp;nbsp;
Beginning Game Development Series


Beginning Game Development Part 1 - Introduction

Beginning Game Development Part II - Introduction to DirectX

Beginning Game Development: Part III - DirectX II

Beginning Game Development: Part IV - DirectInput

Beginning Game Development: Part V - Adding Units


Beginning Game Development: Part VI - Lights, Materials and Terrain

Beginning Game Development: Part VII –Terrain and Collision Detection

Beginning Game Development: Part VIII - DirectSound


Beginning Game Development: Part VIII - DirectSound II




Beginning Game Development: Part VIII - DirectSound III







Part I – Introduction  
Welcome to the first article of an introductory series on game programming using the Microsoft .NET Framework and managed DirectX 9.0.
 
This series as aimed at beginning programmers who are interested in developing a game for their own use with the .NET Framework and DirectX. The goal of this series is to have fun creating a game and learn game development and DirectX along the way. Game
 programming and DirectX have their own terms and definitions that can be difficult to understand, but after awhile, you’ll crack the code and be able to explore a new world of possibilities. I will keep things as straightforward as possible and decode terms
 as they appear. Another part of the learning curve comes from the math you’ll need to deal with DirectX. I am going to point out some resources along the way that will help you brush up on, or learn, the math skills you’ll need to ke</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-I--Introduction</link>
      <pubDate>Fri, 03 Nov 2006 03:51:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-I--Introduction</guid>      
      <dc:creator>Derek Pierson</dc:creator>
      <itunes:author>Derek Pierson</itunes:author>
      <slash:comments>42</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Beginning-Game-Development-Part-I--Introduction/RSS</wfw:commentRss>
      <category>Gaming</category>
      <category>arcade</category>
    </item>    
</channel>
</rss>