<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SDLTutorials.com &#187; C++ tutorials</title>
	<atom:link href="http://www.sdltutorials.com/tag/c-tutorials/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.sdltutorials.com</link>
	<description>SDL Tutorials - Game Tutorials - Programming Tutorials</description>
	<lastBuildDate>Sat, 28 Aug 2010 13:20:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>SDL SoundBank</title>
		<link>http://www.sdltutorials.com/sdl-soundbank/</link>
		<comments>http://www.sdltutorials.com/sdl-soundbank/#comments</comments>
		<pubDate>Fri, 11 Apr 2008 12:59:50 +0000</pubDate>
		<dc:creator>Tim Jones</dc:creator>
				<category><![CDATA[SDL Tutorials]]></category>
		<category><![CDATA[C++ tutorials]]></category>
		<category><![CDATA[game tutorials]]></category>

		<guid isPermaLink="false">http://www.sdltutorials.com/sdl-soundbank/</guid>
		<description><![CDATA[In this side tutorial we are going to be adding a soundbank that will load all of our sounds, and then we call play them via an ID whenever we want. This tutorial will only deal with sounds, not music, and mind you it&#8217;s a very basic tutorial that gets the job done. There is [...]]]></description>
			<content:encoded><![CDATA[<p>In this side tutorial we are going to be adding a soundbank that will load all of our sounds, and then we call play them via an ID whenever we want. This tutorial will only deal with sounds, not music, and mind you it&#8217;s a very basic tutorial that gets the job done. There is much that can be added to this class, for channels, groups and such, but we&#8217;re dealing with basics here. We&#8217;ll base this tutorial off of my <a href="http://www.sdltutorials.com/sdl-events/">SDL Events</a> tutorial. So use those project files if you need something to work off of.</p>
<p>The first thing you need to do is download SDL mixer from the <a href="http://www.libsdl.org">SDL website</a>. It&#8217;s also included in the SDL library I provide on my website. Be sure to put the include files in the same directory as your SDL include files, and your lib files in the same directory as your SDL lib files to make things easier.</p>
<p><span id="more-36"></span><br />
Start by opening your project, and going under the linker settings. Add SDL_mixer after SDLmain, something like:</p>
<p>mingw32<br />
SDLmain<br />
SDL_mixer<br />
SDL</p>
<p>If you don&#8217;t remember where to find all these settings, hope on over to the first tutorial <a href="http://www.sdltutorials.com/sdl-tutorial-basics/">SDL Tutorial Basics</a> to get a refresher on linking. If you have a .lib file, instead of a .a library file, use the browse button to find the library file that way.</p>
<p>Just a little side note here about sounds. SDL_mixer treats any sound in memory as a chunk. This chunk basically contains the frequency data. What&#8217;s nice about SDL_mixer is that it takes this data and sends it to the audio output, meaning it has taken care of all the hard work. So all that we have to do is load our data, from a WAV file for instance, and then send it to SDL_mixer to be played.</p>
<p>First, create two new files, CSoundBank.h and CSoundBank.cpp. Open up the header file first:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#ifndef _CSOUNDBANK_H_</span><br />
&nbsp; &nbsp; <span class="co2">#define _CSOUNDBANK_H_</span></p>
<p><span class="co2">#include &lt;SDL.h&gt;</span><br />
<span class="co2">#include &lt;SDL_mixer.h&gt;</span><br />
<span class="co2">#include &lt;vector&gt;</span></p>
<p><span class="kw2">class</span> CSoundBank <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">static</span> CSoundBank &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SoundControl;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; std::<span class="me2">vector</span>&lt;Mix_Chunk*&gt; &nbsp; &nbsp; SoundList;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; CSoundBank<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> OnLoad<span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> OnCleanup<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> Play<span class="br0">&#40;</span><span class="kw4">int</span> ID<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span>;</p>
<p><span class="co2">#endif</span><br />
&nbsp;</div>
<p>We have a static control object first, this lets us add sounds and play sounds from anywhere in our program. Think of this as your master control for adding/playing sounds. We then have our SoundList, this is a list of SDL mixer sounds. Now, a Mix_Chunk object contains the information needed to play a sound. What we will do later on is load a wav file into a Mix_Chunk object. Think of it as the sound equivalent to SDL_Surface. Then we have some basic functions for loading, cleanup up, and playing a sound. Simple enough.</p>
<p>Next, open up CSoundBank.cpp:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &quot;CSoundBank.h&quot;</span></p>
<p>CSoundBank CSoundBank::<span class="me2">SoundControl</span>;</p>
<p>CSoundBank::<span class="me2">CSoundBank</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">int</span> CSoundBank::<span class="me2">OnLoad</span><span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; Mix_Chunk* TempSound = <span class="kw2">NULL</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>TempSound = Mix_LoadWAV<span class="br0">&#40;</span><span class="kw4">File</span><span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">-1</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; SoundList.<span class="me1">push_back</span><span class="br0">&#40;</span>TempSound<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span>SoundList.<span class="me1">size</span><span class="br0">&#40;</span><span class="br0">&#41;</span> &#8211; <span class="nu0">1</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CSoundBank::<span class="me2">OnCleanup</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> i = <span class="nu0">0</span>;i &lt; SoundList.<span class="me1">size</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;i++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Mix_FreeChunk<span class="br0">&#40;</span>SoundList<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; SoundList.<span class="me1">clear</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CSoundBank::<span class="me2">Play</span><span class="br0">&#40;</span><span class="kw4">int</span> ID<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>ID &lt; <span class="nu0">0</span> || ID &gt;= SoundList.<span class="me1">size</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">return</span>;<br />
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>SoundList<span class="br0">&#91;</span>ID<span class="br0">&#93;</span> == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="kw1">return</span>;</p>
<p>&nbsp; &nbsp; Mix_PlayChannel<span class="br0">&#40;</span><span class="nu0">-1</span>, SoundList<span class="br0">&#91;</span>ID<span class="br0">&#93;</span>, <span class="nu0">0</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>This is also pretty straight forward. We have our static control, our empty constructor, and then our loading function. We basically take the filename of the sound to be loaded, and try to load it via Mix_LoadWAV into the Mix_Chunk object. Notice I am making a temporary object first, and then throwing it into the list. At the very end of the function, I return the ID of the last inserted sound. So, for instance, say I loaded SoundA and SoundB:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw4">int</span> SoundA = CSoundBank::<span class="me2">SoundControl</span>.<span class="me1">OnLoad</span><span class="br0">&#40;</span><span class="st0">&quot;sounda.wav&quot;</span><span class="br0">&#41;</span>;<br />
<span class="kw4">int</span> SoundB = CSoundBank::<span class="me2">SoundControl</span>.<span class="me1">OnLoad</span><span class="br0">&#40;</span><span class="st0">&quot;soundb.wav&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>The ID for playing this sounds later would be returned by the OnLoad function.</p>
<p>Okay, next we have our cleanup function which goes through the list and frees the sound chunks. Simple enough, just like SDL_FreeSurface.</p>
<p>Lastly, we have our Play function that actually plays the sound. We pass an ID (the one we got returned from the Load function) first. We do a little boundary check to make sure the ID is valid, and then actually try to play the sound. The Mix_PlayChannel takes three arguments:</p>
<p>The first specifies which channel to play the sound on, -1 means use the first available.<br />
The second specifies which sound chunk to play.<br />
The last specifies how many times to play this sound (loop). -1 would be infinite.</p>
<p>We haven&#8217;t done much with channels in this class, but the class is easily changeable to add that functionality. Basically, a channel allows you to set certain settings to certain sounds. For instance, you can set volume or panning on the first channel, so any sounds played on that channel would be affected.</p>
<p>So lets do a little test now. Open up CApp.h and add the header file, and add some variables and functions to the class:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &quot;CSoundBank.h&quot;</span></p>
<p><span class="co1">//&#8230;</span></p>
<p><span class="kw2">class</span> CApp <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> SoundA;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> SoundB;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//&#8230; other code</span></p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> OnKeyDown<span class="br0">&#40;</span>SDLKey sym, SDLMod mod, Uint16 unicode<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span>;<br />
&nbsp;</div>
<p>Now, open up CApp_Init.cpp so we can load some sounds:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>SoundA = CSoundBank::<span class="me2">SoundControl</span>.<span class="me1">OnLoad</span><span class="br0">&#40;</span><span class="st0">&quot;sounda.wav&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="nu0">-1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>SoundB = CSoundBank::<span class="me2">SoundControl</span>.<span class="me1">OnLoad</span><span class="br0">&#40;</span><span class="st0">&quot;soundb.wav&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="nu0">-1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>Now, to make sounds when we press a key, open up CApp_OnEvent.cpp and add the function:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw4">void</span> CApp::<span class="me2">OnKeyDown</span><span class="br0">&#40;</span>SDLKey sym, SDLMod mod, Uint16 unicode<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>sym == SDLK_1<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CSoundBank::<span class="me2">SoundControl</span>.<span class="me1">Play</span><span class="br0">&#40;</span>SoundA<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>sym == SDLK_2<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; CSoundBank::<span class="me2">SoundControl</span>.<span class="me1">Play</span><span class="br0">&#40;</span>SoundB<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>We aren&#8217;t done yet, we have to do a little bit to start SDL_mixer. This is just like starting up SDL, but instead we need to start up SDL_mixer to access sounds. Open up CApp_Init.cpp and add the following somewhere after SDL_Init:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw1">if</span><span class="br0">&#40;</span>Mix_OpenAudio<span class="br0">&#40;</span><span class="nu0">44100</span>, MIX_DEFAULT_FORMAT, <span class="nu0">2</span>, <span class="nu0">4096</span><span class="br0">&#41;</span> &lt; <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>Mix_OpenAudio basically Inits SDL_mixer. This function takes 4 arguments. The first is used to specify the frequency, 44100 is usually a good number. But depending on your wav files, you may have to change this. Another common number is 22050. I won&#8217;t get into detail about frequencies and such, just leave it alone unless you really need to change it. The next is the format, again, it&#8217;s best to leave it unless you know much about audio (it&#8217;s basically the size of the samples used, 8bit or 16bit). The next is the number of channels, 1 = mono, 2 = stereo. Note, these channels are different than the other channels I was talking about before. The other channels are &#8220;mixing channels,&#8221; basically streams that I can push audio through. These channels though, are the number of audio outputs. Think of it like the number of speakers that you might have. 2 speakers, 2 channels. The last number is used to set the size of the samples (in bytes). Again, unless you really know what you are doing, it&#8217;s best to leave these numbers alone.</p>
<p>To tidy things up, we need to make sure we stop the SDL_mixer service when we are done, as well as freeing any sounds we may have loaded. So open up CApp_OnCleanup.cpp and add the following:</p>
<div class="dean_ch" style="white-space: wrap;">
CSoundBank::<span class="me2">SoundControl</span>.<span class="me1">OnCleanup</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>Mix_CloseAudio<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>And we are done! Try compiling, and pressing the 1 and 2 keys to here some sounds. If you need some WAV files, download the project files below to grab them.</p>
<p><b>SDL SoundBank &#8211; Tutorial Files:</b><br />
<b>Win32:</b> <a href="../tutorials/sdl-soundbank.zip">Zip</a>, <a href="../tutorials/sdl-soundbank.rar">Rar</a><br />
<b>Linux:</b> <a href="../tutorials/sdl-soundbank.tar.gz">Tar</a> (Thanks Gaten)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sdltutorials.com/sdl-soundbank/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>SDL Maps</title>
		<link>http://www.sdltutorials.com/sdl-maps/</link>
		<comments>http://www.sdltutorials.com/sdl-maps/#comments</comments>
		<pubDate>Sat, 15 Mar 2008 22:35:52 +0000</pubDate>
		<dc:creator>Tim Jones</dc:creator>
				<category><![CDATA[SDL Tutorials]]></category>
		<category><![CDATA[C++ tutorials]]></category>
		<category><![CDATA[game tutorials]]></category>

		<guid isPermaLink="false">http://www.sdltutorials.com/sdl-maps/</guid>
		<description><![CDATA[As I stated in the last lesson, we&#8217;re going to be looking at making a Map class that will be tile based. In addition to the maps, we&#8217;ll be creating Areas that enhouse many Maps. While we could create one giant map, it&#8217;s far easier to manage many smaller maps, and also opens the possibility [...]]]></description>
			<content:encoded><![CDATA[<p>As I stated in the last lesson, we&#8217;re going to be looking at making a Map class that will be tile based. In addition to the maps, we&#8217;ll be creating Areas that enhouse many Maps. While we could create one giant map, it&#8217;s far easier to manage many smaller maps, and also opens the possibility of tiling maps as well. By the way, head on over to the <a href="http://www.sdltutorials.com/sdl-image/">SDL Image tutorial</a> if you haven&#8217;t already done so, we will be making the switch over to SDL Image and stop using SDL_LoadBMP. No more chatter, lets get started.</p>
<p><span id="more-35"></span></p>
<p><br/></p>
<div style="padding: 5px; border: 1px #990033 solid; background-color: ##FFE1E1;">
<b>Known Bug:</b> The camera settings for this tutorial are backwards, and are reversed in the SDL Collision tutorial (and following). Changes are not put in place yet, to get the fixes view the SDL Collision tutorial.
</div>
<p><br/></p>
<p>We&#8217;re going to need several files in the beginning, Define.h, CArea.h, CArea.cpp, CMap.h, CMap.cpp, CTile.h, and CTile.cpp. So create these blank files. What we are going to do is have one Area object, this Area object will have many children Map objects in a vector (like the Entities in a vector). Within each of these Map objects, they will have a vector of each individual tile. So basically, we have a bunch of tiles that make up a map, and a bunch of maps make up an area.</p>
<p><center><img src="../tutorials/7-area.png" alt=""/></center></p>
<p>Lets start by opening up Define.h. This file is going to hold some constant values, as defines, that will define things like map width and height, screen width and height, and tile size. These are going to be some values that we will be using throughout making our Maps and such. Add the following below to define.h.</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#ifndef _DEFINE_H_</span><br />
&nbsp; &nbsp; <span class="co2">#define _DEFINE_H_</span></p>
<p><span class="co2">#define MAP_WIDTH&nbsp; &nbsp;40</span><br />
<span class="co2">#define MAP_HEIGHT&nbsp; 40</span></p>
<p><span class="co2">#define TILE_SIZE&nbsp; &nbsp;16</span></p>
<p><span class="co2">#define WWIDTH&nbsp; &nbsp; &nbsp; 640</span><br />
<span class="co2">#define&nbsp;WHEIGHT&nbsp;&nbsp; &nbsp; 480</span></p>
<p><span class="co2">#endif</span><br />
&nbsp;</div>
<p>We&#8217;ll get back to what these values mean later, but WWIDTH and WHEIGHT are the values set in SDL_SetVideoMode. So open up CApp_Init and change that function call to the following:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>Surf_Display = SDL_SetVideoMode<span class="br0">&#40;</span>WWIDTH, WHEIGHT, <span class="nu0">32</span>, SDL_HWSURFACE | SDL_DOUBLEBUF<span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>Simple enough. Next, open up CTile.h. This class is going to define a single tile on a map. In gaming terms, a tile is basically a single square graphic that we draw to the screen. Remember the animation tutorial, each frame of Yoshi could be thought of as a tile. So when I say we have a map made up of many tiles, we are taking these tiles and repeating them in a grid sequence.</p>
<p>And since we have a single graphic containg all of our tiles, we only have to load one graphic, and not several for each tile. Each tile then needs some properties. The most obvious is which graphical tile to use. Take a look at an example tileset below:</p>
<p><center><img src="../tutorials/7-tileset.png" alt=""/></center></p>
<p>You&#8217;ll notice that the very top left has an ID of 0, and going to the left it increments in 1s.  This is called the Tile ID. By using the ID, and the size of each tile (TILE_SIZE), we can know which tile to draw to the screen. The next important thing is TypeID. This determines what type of tile it is. Some examples might be, invisible (don&#8217;t draw a tile), block (like a wall), or ground (player can walk on it). You can define whatever TypeIDs you want, but these are the most basic (other examples might be water, fire, ice, etc&#8230;). That&#8217;s basically it, this Tile class only has two members (for now, later on it will contain information for animated tiles). So lets push this class together inside of CTile.h:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#ifndef _CTILE_H_</span><br />
&nbsp; &nbsp; <span class="co2">#define _CTILE_H_</span></p>
<p><span class="co2">#include &quot;Define.h&quot;</span></p>
<p><span class="kw2">enum</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; TILE_TYPE_NONE = <span class="nu0">0</span>,</p>
<p>&nbsp; &nbsp; TILE_TYPE_NORMAL,<br />
&nbsp; &nbsp; TILE_TYPE_BLOCK<br />
<span class="br0">&#125;</span>;</p>
<p><span class="kw2">class</span> CTile <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> &nbsp; &nbsp; TileID;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> &nbsp; &nbsp; <span class="kw2">TypeID</span>;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; CTile<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span>;</p>
<p><span class="co2">#endif</span></div>
<p>Notice the enum used. This lets us assign or check the TypeID, and know what it is at the same time. So if I did TypeID == TILE_TYPE_BLOCK, I would be able to notice in my code that I am checking for a block type of tile. TypeID == 2 isn&#8217;t as easy to interpret. If you never used enums, think of them like const variables. The value never changes. Also, the starting value defines the rest, notice I have = 0 on TILE_TYPE_NONE. From there the rest of the variables would automatically be assigned values in increments of 1.</p>
<p>Now, lets open up CTile.cpp and finish the code:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &quot;CTile.h&quot;</span></p>
<p>CTile::<span class="me2">CTile</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; TileID = <span class="nu0">0</span>;<br />
&nbsp; &nbsp; <span class="kw2">TypeID</span> = TILE_TYPE_NONE;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>Pretty straight forward. Next, lets look at making some maps. The first thing we need to consider is that our maps will be text files. So we need to come up with a file format, that way we can easily edit our maps outside of our code. And possibly later you could create a map editor.</p>
<p>Each map is going to have a width and height, defining the number of tiles. So a map of 10&#215;10, would have 100 tiles in it. We are going to make all of our maps the same width and height, so we don&#8217;t have to define that within the map files (MAP_WIDTH and MAP_HEIGHT). The part that we do need to add though is the TileID and TypeID for each individual tile. We are going to use the file format that I came up with, as it is relatively simple. Take a look at the 5&#215;5 map example below:</p>
<p>0:0 0:0 0:0 0:0 0:0<br />
1:0 1:0 1:0 0:0 0:0<br />
1:0 1:0 1:0 0:0 0:0<br />
1:0 1:0 1:0 0:0 0:0<br />
1:0 1:0 1:0 0:0 0:0</p>
<p>Each tile within the file would consist of 0:0, effectively being the TileID:TypeID. A space would be the deliminator between the tiles. A concept rendering if this map may look like this:</p>
<p><center><img src="../tutorials/7-map.png" alt=""/></center></p>
<p>For this tutorial we will be using 40&#215;40 maps, since that is a pretty decent size. And instead of printing an example out for you to copy, click on this link here:</p>
<p><a href="../tutorials/1.map">Example Map</a></p>
<p>First create a folder in the same directory as your exe called maps. This folder is where all your maps will be. Save that map as 1.map. Also, make another folder called tilesets in the same directory as your exe, and save the tileset above as 1.png.</p>
<p>Now that we have a file format for our maps, lets start designing the class that will render this thing. Open up CMap.h:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#ifndef _CMAP_H_</span><br />
&nbsp; &nbsp; <span class="co2">#define _CMAP_H_</span></p>
<p><span class="co2">#include &lt;SDL.h&gt;</span><br />
<span class="co2">#include &lt;vector&gt;</span></p>
<p><span class="co2">#include &quot;CTile.h&quot;</span><br />
<span class="co2">#include &quot;CSurface.h&quot;</span></p>
<p><span class="kw2">class</span> CMap <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; SDL_Surface* Surf_Tileset;</p>
<p>&nbsp; &nbsp; <span class="kw2">private</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; std::<span class="me2">vector</span>&lt;CTile&gt; TileList;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; CMap<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">bool</span> OnLoad<span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> OnRender<span class="br0">&#40;</span>SDL_Surface* Surf_Display, <span class="kw4">int</span> MapX, <span class="kw4">int</span> MapY<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span>;</p>
<p><span class="co2">#endif</span><br />
&nbsp;</div>
<p>A few of the basic things are here, OnLoad and OnRender. OnLoad does what you expect, loads a map from a file, and populates the TileList. The OnRender also does what you expect, properly puts each tile on the screen and draws them using the Surf_Tileset. Lets define what these functions do, now open up CMap.cpp:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &quot;CMap.h&quot;</span></p>
<p>CMap::<span class="me2">CMap</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; Surf_Tileset = <span class="kw2">NULL</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">bool</span> CMap::<span class="me2">OnLoad</span><span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; TileList.<span class="me1">clear</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw4">FILE</span>* FileHandle = <span class="kw3">fopen</span><span class="br0">&#40;</span><span class="kw4">File</span>, <span class="st0">&quot;r&quot;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>FileHandle == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> Y = <span class="nu0">0</span>;Y &lt; MAP_HEIGHT;Y++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> X = <span class="nu0">0</span>;X &lt; MAP_WIDTH;X++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CTile tempTile;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">fscanf</span><span class="br0">&#40;</span>FileHandle, <span class="st0">&quot;%d:%d &quot;</span>, &amp;tempTile.<span class="me1">TileID</span>, &amp;tempTile.<span class="kw2">TypeID</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TileList.<span class="me1">push_back</span><span class="br0">&#40;</span>tempTile<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">fscanf</span><span class="br0">&#40;</span>FileHandle, <span class="st0">&quot;<span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw3">fclose</span><span class="br0">&#40;</span>FileHandle<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">true</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CMap::<span class="me2">OnRender</span><span class="br0">&#40;</span>SDL_Surface* Surf_Display, <span class="kw4">int</span> MapX, <span class="kw4">int</span> MapY<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>Surf_Tileset == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="kw1">return</span>;</p>
<p>&nbsp; &nbsp; <span class="kw4">int</span> TilesetWidth &nbsp;= Surf_Tileset-&gt;w / TILE_SIZE;<br />
&nbsp; &nbsp; <span class="kw4">int</span> TilesetHeight = Surf_Tileset-&gt;h / TILE_SIZE;</p>
<p>&nbsp; &nbsp; <span class="kw4">int</span> ID = <span class="nu0">0</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> Y = <span class="nu0">0</span>;Y &lt; MAP_HEIGHT;Y++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> X = <span class="nu0">0</span>;X &lt; MAP_WIDTH;X++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>TileList<span class="br0">&#91;</span>ID<span class="br0">&#93;</span>.<span class="kw2">TypeID</span> == TILE_TYPE_NONE<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ID++;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">continue</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> tX = MapX + <span class="br0">&#40;</span>X * TILE_SIZE<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> tY = MapY + <span class="br0">&#40;</span>Y * TILE_SIZE<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> TilesetX = <span class="br0">&#40;</span>TileList<span class="br0">&#91;</span>ID<span class="br0">&#93;</span>.<span class="me1">TileID</span> % TilesetWidth<span class="br0">&#41;</span> * TILE_SIZE;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> TilesetY = <span class="br0">&#40;</span>TileList<span class="br0">&#91;</span>ID<span class="br0">&#93;</span>.<span class="me1">TileID</span> / TilesetWidth<span class="br0">&#41;</span> * TILE_SIZE;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CSurface::<span class="me2">OnDraw</span><span class="br0">&#40;</span>Surf_Display, Surf_Tileset, tX, tY, TilesetX, TilesetY, TILE_SIZE, TILE_SIZE<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ID++;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p><br/></p>
<div style="padding: 5px; border: 1px #990033 solid; background-color: ##FFE1E1;">
<b>Bug Fix:</b> There was a bug in the continue within the loop, we should be incrementing the ID before continuing. Thanks Zakalwe for helping find this bug!<br />
<br/><br />
<b>Bug Fix:</b> We should been dividing by TilesetWidth for TilesetY, otherwise it will not correctly grab the correct Y coordinate unless the Tileset is square. Thanks <a href="http://www.animea.net">Anime</a> for helping find this bug!</div>
<p><br/></p>
<p>Lets start at the top. The constructor sets the Tileset to NULL, obviously. Next we have the OnLoad function. First, we are clearing out any old tiles, that way if we load twice, it won&#8217;t have double the amount of tiles, effectively loading a new map. We then open up a FileHandle, and try to open the requested map file. Now, we go through the map file and grab each tile. This is accomplished by using the two loops. The outer loop is the Y axis loop, going from the top row to the bottom row of the map file. The inner loop is the X axis loop, going from the left most tile, to the right most tile. Pay attention to how this loop works, because it is also used below in the OnRender function. It basically goes from the top left tile, to the bottom right tile, 1 tile at a time. Inside of those loops we create a temporary tile, and load the file information into it. We then push that into our TileList, effectively saving the tile. We close the filehandle, and we are done.</p>
<p>Next, we have the function to render a map. Notice the MapX and MapY arguments. These tell use where to render this map on the screen. This is useful later on for moving maps around. First in the function we check for a valid tileset, because we are going to access this tileset directly and don&#8217;t want to cause a crash. We then grab the TilesetWidth and TilesetHeight in Tiles. This is important, because we need to know how many tiles a tileset contains, not its actual width and height. That way we can match up a TileID to a tileset. So, a Tileset with a Width and Height, in tiles, of 2&#215;2, would have 4 tiles on it, but in reality it would be 32&#215;32 pixels. So, a TileID of 0 would match the first tile, a TileID of 1 would be the next, and so on. TileIDs repeat on the next row, from left to right.</p>
<p>Okay, next we have that same loop again, going through each tile (Please note that these X and Y coordinates here in the loop are also in number of tiles, they aren&#8217;t actual pixels). This time, however, we have an ID variable. This ID is incremented by one each loop, and will allow us to grab each tile in the map. So, first we check to see if this Tile should even be drawn, by checking the TypeID. If it is TILE_TYPE_NONE, we skip over it with continue. After that we figure out where to draw this tile on the screen. This is done by taking the MapX and MapY (effectively offset coordinates, because they offset a map from 0, 0 to somewhere, which makes it seem like a map is moving), and taking the X and Y coordinates in the loop. We have to convert these X and Y coordinates back to pixel coordinates, which is done by multiplying it by the size of a tile.</p>
<p>After that, we do something with the Tileset. What we are doing is calculating where on the Tileset to grab the appropriate tile. This is by grabing the TileID of the tile first, and then converting that to a Tile coordinate. A little bit of explanation here. We have our 2&#215;2 tileset, and a TileID of 1. Figuring out X, we would get 1 % 2, which would be 1 still. We when multiply that by the TILE_SIZE, and get 16. That is the correct X coordinate for the Tile. Same with the Y, we put 1 / 2, which is 0.5. Since this an integer operation, the .5 is automatically dropped. Thus we are left with 0. Which is also the correct row. Now, say we had a TileID of 2. 2 % 2 = 0, and 2 / 2 = 1. See how the X repeats in a pattern? 0, 1, 0, 1&#8230; And notice how Y increases every time it goes past the Tileset Width? 0, 0, 1, 1. I hope this is clear, as it is somewhat hard to explain.</p>
<p>Next, we actually draw the tile to the screen using the coordinates we just calculated, and then increase the ID to go to the next tile. A little side note here, we could, for the sake of speed, create an OnRender_Cache function that would perform this same operation, but would draw to a Surface defined in the CMap class. Something like SDL_Surface* Surf_Map. Then, the OnRender function would render the Surf_Map only, and not perform any operations. But also take note that that method does not necessarely work later on when we want to animate tiles.</p>
<p>Okay, cool! I know that is quite a bit to take in at once, but don&#8217;t fret! It&#8217;s really not too bad once you get the hang of it. I want to say that right now we could create Map objects and render maps just fine. This would be ideal for games like Mario and Megaman, as they are just one big map. But for games like Zelda and Metroid, it won&#8217;t work too well. That is where Areas come in. Just like maps having file formats, each area will have its own file and file format. Each area is going to have a tileset to load, the size of the area, and the maps that are to be loaded in each area. Here is the area we are going to be using below:</p>
<p>./tilesets/1.png<br />
3<br />
./maps/1.map ./maps/1.map ./maps/1.map<br />
./maps/1.map ./maps/1.map ./maps/1.map<br />
./maps/1.map ./maps/1.map ./maps/1.map </p>
<p>Save this into a file called 1.area, and save it in your maps directory. Just like maps, this area will tile maps. I won&#8217;t get into detail because I think you all have the point by now.</p>
<p>Open up CArea.h and lets begin:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#ifndef _CAREA_H_</span><br />
&nbsp; &nbsp; <span class="co2">#define _CAREA_H_</span></p>
<p><span class="co2">#include &quot;CMap.h&quot;</span></p>
<p><span class="kw2">class</span> CArea <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">static</span> CArea &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;AreaControl;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; std::<span class="me2">vector</span>&lt;CMap&gt; &nbsp; &nbsp; &nbsp; MapList;</p>
<p>&nbsp; &nbsp; <span class="kw2">private</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AreaSize;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; SDL_Surface*&nbsp; &nbsp; &nbsp; &nbsp; Surf_Tileset;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; CArea<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">bool</span> &nbsp; &nbsp;OnLoad<span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> &nbsp; &nbsp;OnRender<span class="br0">&#40;</span>SDL_Surface* Surf_Display, <span class="kw4">int</span> CameraX, <span class="kw4">int</span> CameraY<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> &nbsp; &nbsp;OnCleanup<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span>;</p>
<p><span class="co2">#endif</span><br />
&nbsp;</div>
<p>This class is going to similar to the Map class in some ways, but different in others. Similarly, we have MapList that will hold our maps, just like the Map class had a list of tiles. Also, as have a Load function and Render function. Now the differences, we have a static AreaControl, much like Entities have a static control. This will allow us to manipulate an Area from any class by using this object. Next, we have the AreaSize which is the number of maps. We are going to assume that areas will always be square, so an AreaSize of 3, would be a 3&#215;3 area. If you wanted to, and I don&#8217;t think it&#8217;s necessary, you would have AreaWidth and AreaHeight. Next, we have a surface for the Tileset. You probably noticed that within the CMap class we never actually loaded a tileset. That&#8217;s because the Area is going to do it for us, and then pass that pointer to the CMap class. That way each map doesn&#8217;t load a tileset for itself, but effectively all maps share the same tileset. Again, if you wanted each Map to have its own tileset you can easily modify the class to do so.</p>
<p>Okay, now open up the CArea.cpp class:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &quot;CArea.h&quot;</span></p>
<p>CArea CArea::<span class="me2">AreaControl</span>;</p>
<p>CArea::<span class="me2">CArea</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; AreaSize = <span class="nu0">0</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">bool</span> CArea::<span class="me2">OnLoad</span><span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; MapList.<span class="me1">clear</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw4">FILE</span>* FileHandle = <span class="kw3">fopen</span><span class="br0">&#40;</span><span class="kw4">File</span>, <span class="st0">&quot;r&quot;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>FileHandle == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw4">char</span> TilesetFile<span class="br0">&#91;</span><span class="nu0">255</span><span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw3">fscanf</span><span class="br0">&#40;</span>FileHandle, <span class="st0">&quot;%s<span class="es0">\n</span>&quot;</span>, TilesetFile<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>Surf_Tileset = CSurface::<span class="me2">OnLoad</span><span class="br0">&#40;</span>TilesetFile<span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="kw2">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">fclose</span><span class="br0">&#40;</span>FileHandle<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw3">fscanf</span><span class="br0">&#40;</span>FileHandle, <span class="st0">&quot;%d<span class="es0">\n</span>&quot;</span>, &amp;AreaSize<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> X = <span class="nu0">0</span>;X &lt; AreaSize;X++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> Y = <span class="nu0">0</span>;Y &lt; AreaSize;Y++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">char</span> MapFile<span class="br0">&#91;</span><span class="nu0">255</span><span class="br0">&#93;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">fscanf</span><span class="br0">&#40;</span>FileHandle, <span class="st0">&quot;%s &quot;</span>, MapFile<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CMap tempMap;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>tempMap.<span class="me1">OnLoad</span><span class="br0">&#40;</span>MapFile<span class="br0">&#41;</span> == <span class="kw2">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">fclose</span><span class="br0">&#40;</span>FileHandle<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tempMap.<span class="me1">Surf_Tileset</span> = Surf_Tileset;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MapList.<span class="me1">push_back</span><span class="br0">&#40;</span>tempMap<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">fscanf</span><span class="br0">&#40;</span>FileHandle, <span class="st0">&quot;<span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw3">fclose</span><span class="br0">&#40;</span>FileHandle<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">true</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CArea::<span class="me2">OnRender</span><span class="br0">&#40;</span>SDL_Surface* Surf_Display, <span class="kw4">int</span> CameraX, <span class="kw4">int</span> CameraY<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> MapWidth &nbsp;= MAP_WIDTH * TILE_SIZE;<br />
&nbsp; &nbsp; <span class="kw4">int</span> MapHeight = MAP_HEIGHT * TILE_SIZE;</p>
<p>&nbsp; &nbsp; <span class="kw4">int</span> FirstID = -CameraX / MapWidth;<br />
&nbsp; &nbsp; &nbsp; &nbsp; FirstID = FirstID + <span class="br0">&#40;</span><span class="br0">&#40;</span>-CameraY / MapHeight<span class="br0">&#41;</span> * AreaSize<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> i = <span class="nu0">0</span>;i &lt; <span class="nu0">4</span>;i++<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> ID = FirstID + <span class="br0">&#40;</span><span class="br0">&#40;</span>i / <span class="nu0">2</span><span class="br0">&#41;</span> * AreaSize<span class="br0">&#41;</span> + <span class="br0">&#40;</span>i % <span class="nu0">2</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>ID &lt; <span class="nu0">0</span> || ID &gt;= MapList.<span class="me1">size</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">continue</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> X = <span class="br0">&#40;</span><span class="br0">&#40;</span>ID % AreaSize<span class="br0">&#41;</span> * MapWidth<span class="br0">&#41;</span> + CameraX;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> Y = <span class="br0">&#40;</span><span class="br0">&#40;</span>ID / AreaSize<span class="br0">&#41;</span> * MapHeight<span class="br0">&#41;</span> + CameraY;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; MapList<span class="br0">&#91;</span>ID<span class="br0">&#93;</span>.<span class="me1">OnRender</span><span class="br0">&#40;</span>Surf_Display, X, Y<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CArea::<span class="me2">OnCleanup</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>Surf_Tileset<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; SDL_FreeSurface<span class="br0">&#40;</span>Surf_Tileset<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; MapList.<span class="me1">clear</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>Quickly, going from the top, we declare the static object, and then set the AreaSize to 0. Then we have our Load function. It works just like the Load function within CMap, except there are a few differences. We have to load tileset first. We try to load this tileset into the surface, and if it fails return false. We then load the size of the Area. Okay, after that we have two loops, just like maps, that will go through and grab each map filename. It will then create a map object, load the map, set the tileset to be used, and then push it into the list. Pretty simply and straight forward.</p>
<p>Next, we have the Render function. We calculate the actual Map width and height, in pixels, first. This will let us find the first map to render. Some explanation first of what I am trying to do. Since an area can be of any size, like 100&#215;100 maps, we don&#8217;t want to go through all the trouble and render every single map. We only want to render the maps that are visible in the screen area. For our size of a screen, 640&#215;480, only a possible 4 maps can be visible at one time (like standing at the corner of 4 maps). So what we have to do is calculate the first Map ID to grab. This is going to the first map to render. From the first ID, we know the next 3 maps to render. The one to the right of the first map, the one at the bottom of the first map, and the one at the bottom right of the first map. How is that accomplished? Look at the image below:</p>
<p><center><img src="../tutorials/7-area-camera.png" alt=""/></center></p>
<p>We have a guy, the circle, in the very center of the screen, represented by the red square. The other squares are each Map, and we have a Camera position of -700, -700. Why negative? Think about it, the screen itself never really moves, everything else does. So, for something to move up, it must increase its Y in the negative direction. Same with the X coordinate. So, to get to the 4th map, we have to move the area in the negative direction. Now, notice the grayed out maps, these are maps not visible within the players view, so they shouldn&#8217;t be rendered. To figure out the First ID, which is 4 in this case, we need to use the specified Camera coordinates. We translate those Camera coordinates into Map coordinates. So, taking -(-700) / 640 (which is 40 * 16, remember the MapWidth calculation done above) we get 1 (dropping the decimal because its an integer operation). This is the X coordinate in Maps, but we aren&#8217;t done. We then calculate the Y coordinate in Maps the same way -(-700) / 640, but we multiply that by the AreaSize. That&#8217;s because we are grabbing the ID. So, it would become 1 * 3, which is 3, and adding that to the first calculation of 1, we get 4. And what do you know, the First ID on the map!</p>
<p>Okay, so we go through each of the four maps now. Since I did a regular loop of i < 4, we need to figure out how to add that to the First ID, to actually figure out each of the four Map IDs. This is done by taking the First ID as an offset first. We then take i, our position in the loop, divide by two and multiply by the area size. What does this do? Much like the Map class, it creates a pattern, 0, 0, 1, 1. Same with the last operation i % 2, it creates a pattern of  0, 1, 0, 1. This then gives us the correct pattern of, 4, 5, 7, 8. Which are the correct map to render.</p>
<p>We do a little check to make sure the ID is good, since the ID may not exist. And now the last calculation (yes, I know, a lot of complex calculations). It works just like the way we calculated which tile to grab on the tileset. It's turning an ID into actual pixel coordinates, and then offsetting those coordinates by the camera (making it seem like it moved). We then finally render the map, passing the coordinates of where to draw it.</p>
<p>Lastly, we have our cleanup function that frees the surface and clears the maps.</p>
<p>What a load! I hope all of the various calculations don't get you confused. There are really only two basic things we are trying to do, turn pixel coordinates into grid based coordinates. Such as with tiles, and with the maps. The other thing was turning those grid based coordinates back and forth into IDs. </p>
<p>Okay, we are not quite done yet, still a little bit to do (now you see why this tutorial took so long to complete!). You may have noticed that I called the arguments on the Render function on the CArea class CameraX and CameraY. We are going to need to make a camera class that defines the viewing area. This is what we are going to manipulate to move around on a map!</p>
<p>So create two new files, CCamera.cpp and CCamera.h. Open up the header file first:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#ifndef _CCAMERA_H_</span><br />
&nbsp; &nbsp; <span class="co2">#define _CCAMERA_H_</span></p>
<p><span class="co2">#include &lt;SDL.h&gt;</span></p>
<p><span class="co2">#include &quot;Define.h&quot;</span></p>
<p><span class="kw2">enum</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; TARGET_MODE_NORMAL = <span class="nu0">0</span>,<br />
&nbsp; &nbsp; TARGET_MODE_CENTER<br />
<span class="br0">&#125;</span>;</p>
<p><span class="kw2">class</span> CCamera <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">static</span> CCamera CameraControl;</p>
<p>&nbsp; &nbsp; <span class="kw2">private</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> X;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> Y;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span>* TargetX;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span>* TargetY;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> TargetMode;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; CCamera<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> OnMove<span class="br0">&#40;</span><span class="kw4">int</span> MoveX, <span class="kw4">int</span> MoveY<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> GetX<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> GetY<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw2">public</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> SetPos<span class="br0">&#40;</span><span class="kw4">int</span> X, <span class="kw4">int</span> Y<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span> SetTarget<span class="br0">&#40;</span><span class="kw4">int</span>* X, <span class="kw4">int</span>* Y<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span>;</p>
<p><span class="co2">#endif</span><br />
&nbsp;</div>
<p>First, we have a control member object, just like area. Then we have the coordinates of where the camera is. An extra thing I threw in, was the ability to target something. For example, in a Megaman game the camera would target Megaman himself. That way, when Megaman moves the camera would automatically update. So we have two pointers for X and Y coordinates. If these are null, the camera will automatically revert to the cameras position. Next, we have a target mode, which, for now, is either normal (the camera will position to the top left of the target) or center (will center the camera to the target). Pretty simply I think.</p>
<p>We then have a few functions, the first is the OnMove, which will increase the X and Y of the camera by MoveX and MoveY. So OnMove(0, -1) would move the camera to the left one pixel. We then have Get functions for the coordinates, and the ability to set the coordinates and set a target.</p>
<p>Okay, now open up CCamera.cpp:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &quot;CCamera.h&quot;</span></p>
<p>CCamera CCamera::<span class="me2">CameraControl</span>;</p>
<p>CCamera::<span class="me2">CCamera</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; X = Y = <span class="nu0">0</span>;</p>
<p>&nbsp; &nbsp; TargetX = TargetY = <span class="kw2">NULL</span>;</p>
<p>&nbsp; &nbsp; TargetMode = TARGET_MODE_NORMAL;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CCamera::<span class="me2">OnMove</span><span class="br0">&#40;</span><span class="kw4">int</span> MoveX, <span class="kw4">int</span> MoveY<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; X += MoveX;<br />
&nbsp; &nbsp; Y += MoveY;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">int</span> CCamera::<span class="me2">GetX</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>TargetX != <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>TargetMode == TARGET_MODE_CENTER<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> *TargetX &#8211; <span class="br0">&#40;</span>WWIDTH / <span class="nu0">2</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> *TargetX;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> X;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">int</span> CCamera::<span class="me2">GetY</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>TargetY != <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>TargetMode == TARGET_MODE_CENTER<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> *TargetY &#8211; <span class="br0">&#40;</span>WHEIGHT / <span class="nu0">2</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> *TargetY;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> Y;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CCamera::<span class="me2">SetPos</span><span class="br0">&#40;</span><span class="kw4">int</span> X, <span class="kw4">int</span> Y<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; this-&gt;X = X;<br />
&nbsp; &nbsp; this-&gt;Y = Y;<br />
<span class="br0">&#125;</span></p>
<p><span class="kw4">void</span> CCamera::<span class="me2">SetTarget</span><span class="br0">&#40;</span><span class="kw4">int</span>* X, <span class="kw4">int</span>* Y<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; TargetX = X;<br />
&nbsp; &nbsp; TargetY = Y;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>From top to bottom, like usual, we have are static member first. We then have the constructor defaulting some variables. The OnMove function will increase the X and Y, like I said before. We then have GetX. It will check to see if we have a valid target, and if so return the targets coordinates as the camera coordinates, otherwise return the camera x. For centering mode, we take the screen width and divide by two to find the center of the screen, and then subtract it from the target coordinates. This will center the camera to the target. We then have the SetPos and SetTarget functions, which are self-explanatory.</p>
<p>So lets put all this junk together! Open up CApp.h and modify it to include the new header files:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#include &quot;Define.h&quot;</span></p>
<p><span class="co2">#include &quot;CArea.h&quot;</span><br />
<span class="co2">#include &quot;CCamera.h&quot;</span><br />
&nbsp;</div>
<p>Also, add a new function prototype:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw4">void</span> OnKeyDown<span class="br0">&#40;</span>SDLKey sym, SDLMod mod, Uint16 unicode<span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>We are going to checking that event for move our map around with the keyboard. So, open up CApp_OnEvent.cpp and add the function:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw4">void</span> CApp::<span class="me2">OnKeyDown</span><span class="br0">&#40;</span>SDLKey sym, SDLMod mod, Uint16 unicode<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">switch</span><span class="br0">&#40;</span>sym<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> SDLK_UP: &nbsp; &nbsp;CCamera::<span class="me2">CameraControl</span>.<span class="me1">OnMove</span><span class="br0">&#40;</span> <span class="nu0">0</span>, &nbsp;<span class="nu0">5</span><span class="br0">&#41;</span>; <span class="kw2">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> SDLK_DOWN: &nbsp;CCamera::<span class="me2">CameraControl</span>.<span class="me1">OnMove</span><span class="br0">&#40;</span> <span class="nu0">0</span>, <span class="nu0">-5</span><span class="br0">&#41;</span>; <span class="kw2">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> SDLK_LEFT: &nbsp;CCamera::<span class="me2">CameraControl</span>.<span class="me1">OnMove</span><span class="br0">&#40;</span> <span class="nu0">5</span>, &nbsp;<span class="nu0">0</span><span class="br0">&#41;</span>; <span class="kw2">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> SDLK_RIGHT: CCamera::<span class="me2">CameraControl</span>.<span class="me1">OnMove</span><span class="br0">&#40;</span><span class="nu0">-5</span>, &nbsp;<span class="nu0">0</span><span class="br0">&#41;</span>; <span class="kw2">break</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span>: <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>We check the SDL keys, and according to the key move the camera around. Next, open up CApp_OnCleanup.cpp and add the cleanup function for the Area:</p>
<div class="dean_ch" style="white-space: wrap;">
CArea::<span class="me2">AreaControl</span>.<span class="me1">OnCleanup</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>Open up CApp_OnRender.cpp and add the Render call too:</p>
<div class="dean_ch" style="white-space: wrap;">
CArea::<span class="me2">AreaControl</span>.<span class="me1">OnRender</span><span class="br0">&#40;</span>Surf_Display, CCamera::<span class="me2">CameraControl</span>.<span class="me1">GetX</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, CCamera::<span class="me2">CameraControl</span>.<span class="me1">GetY</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>Notice that we are passing the Camera coordinates to the OnRender. And lastly, open up CApp_OnInit.cpp:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw1">if</span><span class="br0">&#40;</span>CArea::<span class="me2">AreaControl</span>.<span class="me1">OnLoad</span><span class="br0">&#40;</span><span class="st0">&quot;./maps/1.area&quot;</span><span class="br0">&#41;</span> == <span class="kw2">false</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
<span class="br0">&#125;</span></p>
<p>SDL_EnableKeyRepeat<span class="br0">&#40;</span><span class="nu0">1</span>, SDL_DEFAULT_REPEAT_INTERVAL / <span class="nu0">3</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>SDL_EnableKeyRepeat call sets the keyboard repeat count. So if we hold down a key it will keep calling the event above. And we are done! Compile the code and try it out. I hope it all works as expected, this was a very lengthy tutorial. Please check out the tutorial files below if you are having a bit of trouble. And please let me know if for some reason I left some important code out.</p>
<p><b>SDL Maps &#8211; Tutorial Files:</b><br />
<b>Win32:</b> <a href="../tutorials/sdl-maps.zip">Zip</a>, <a href="../tutorials/sdl-maps.rar">Rar</a><br />
<b>Linux:</b> <a href="../tutorials/sdl-maps.tar.gz">Tar</a> (Thanks Gaten), <a href="../tutorials/sdl-maps-compiled.tar.gz">Binary</a> (Thanks Thomas)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sdltutorials.com/sdl-maps/feed/</wfw:commentRss>
		<slash:comments>89</slash:comments>
		</item>
		<item>
		<title>SDL Image</title>
		<link>http://www.sdltutorials.com/sdl-image/</link>
		<comments>http://www.sdltutorials.com/sdl-image/#comments</comments>
		<pubDate>Fri, 14 Mar 2008 11:46:03 +0000</pubDate>
		<dc:creator>Tim Jones</dc:creator>
				<category><![CDATA[SDL Tutorials]]></category>
		<category><![CDATA[C++ tutorials]]></category>
		<category><![CDATA[game tutorials]]></category>

		<guid isPermaLink="false">http://www.sdltutorials.com/sdl-image/</guid>
		<description><![CDATA[This side tutorial is rather simple, short, and sweet. I am going to show you how to stop using those pesky bitmap (BMP) files that are too big and don&#8217;t support alpha transparency, and to start using other file formats for you surfaces (I personally like PNG). If you have not read my SDL Coordinates [...]]]></description>
			<content:encoded><![CDATA[<p>This side tutorial is rather simple, short, and sweet. I am going to show you how to stop using those pesky bitmap (BMP) files that are too big and don&#8217;t support alpha transparency, and to start using other file formats for you surfaces (I personally like PNG). If you have not read my <a href="http://www.sdltutorials.com/sdl-coordinates-and-blitting/">SDL Coordinates and Bliting</a> tutorial, I encourage you to do so now. We will be building off of that tutorial, modifying the OnLoad function of the CSurface class.</p>
<p>The first thing you need to do is download SDL_image, the latest version, from the main <a href="http://www.libsdl.org">SDL website</a>. You can also download this library from the &#8220;Libraries&#8221; section of this website, under SDL. If you don&#8217;t want to worry about finding all these libraries, the SDL package I provide is good for most SDL beginners, as it provides SDL_image, and some other useful libraries. Be sure to put the include files in the same directory as your SDL include files, and your lib files in the same directory as your SDL lib files to make things easier.</p>
<p><span id="more-34"></span><br />
Start by opening your project, and going under the linker settings. Add SDL_image after SDLmain, something like:</p>
<p>mingw32<br />
SDLmain<br />
SDL_image<br />
SDL</p>
<p>If you don&#8217;t remember where to find all these settings, hope on over to the first tutorial <a href="http://www.sdltutorials.com/sdl-tutorial-basics/">SDL Tutorial Basics</a> to get a refresher on linking.</p>
<p>First, open up CSurface.h, so that we can include an extra header file:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="co2">#ifndef _CSURFACE_H_</span><br />
&nbsp; &nbsp; <span class="co2">#define _CSURFACE_H_</span></p>
<p><span class="co2">#include &lt;SDL.h&gt;</span><br />
<span class="co2">#include &lt;SDL_image.h&gt;</span><br />
&nbsp;</div>
<p>Once that is all done, open up CSurface.cpp and look for the OnLoad function. Currently, this is what our code looks like:</p>
<div class="dean_ch" style="white-space: wrap;">
SDL_Surface* CSurface::<span class="me2">OnLoad</span><span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; SDL_Surface* Surf_Temp = <span class="kw2">NULL</span>;<br />
&nbsp; &nbsp; SDL_Surface* Surf_Return = <span class="kw2">NULL</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>Surf_Temp = SDL_LoadBMP<span class="br0">&#40;</span><span class="kw4">File</span><span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">NULL</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; Surf_Return = SDL_DisplayFormat<span class="br0">&#40;</span>Surf_Temp<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; SDL_FreeSurface<span class="br0">&#40;</span>Surf_Temp<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> Surf_Return;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>There are two changes to make here, the first is changing SDL_LoadBMP to IMG_Load. The second is changing SDL_DisplayFormat to SDL_DisplayFormatAlpha. Remember I said BMPs don&#8217;t support alpha layers? Well, PNGs do! And if you are wanting to keep that alpha layer you&#8217;ll need to use SDL_DisplayFormatAlpha instead of SDL_DisplayFormat. So, our code should look like this now:</p>
<div class="dean_ch" style="white-space: wrap;">
SDL_Surface* CSurface::<span class="me2">OnLoad</span><span class="br0">&#40;</span><span class="kw4">char</span>* <span class="kw4">File</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; SDL_Surface* Surf_Temp = <span class="kw2">NULL</span>;<br />
&nbsp; &nbsp; SDL_Surface* Surf_Return = <span class="kw2">NULL</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>Surf_Temp = IMG_Load<span class="br0">&#40;</span><span class="kw4">File</span><span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">NULL</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; Surf_Return = SDL_DisplayFormatAlpha<span class="br0">&#40;</span>Surf_Temp<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; SDL_FreeSurface<span class="br0">&#40;</span>Surf_Temp<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">return</span> Surf_Return;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>Finally, don&#8217;t forget to change the filename that the Test Surface is trying to load in CApp_OnInit.cpp:</p>
<div class="dean_ch" style="white-space: wrap;">
<span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#40;</span>Surf_Test = CSurface::<span class="me2">OnLoad</span><span class="br0">&#40;</span><span class="st0">&quot;myimage.png&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> == <span class="kw2">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">false</span>;<br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>And we are done! I told you it would be short. Try compiling, and trying out different file formats. Some common formats supported by SDL_image are:</p>
<p>BMP (Go figure)<br />
GIF<br />
PNG<br />
JPG<br />
PCX<br />
TIF<br />
and others&#8230;</p>
<p>Please note that there are additional DLL files associated with SDL image that are needed now (about 5 of them). So be sure to include those with your project. You can download these DLL files here, <a href="http://www.libsdl.org/projects/SDL_image/">http://www.libsdl.org/projects/SDL_image/</a> under Binary -> Win32 -> and the Win32 zip (not the VC8). Also, the DLL files are also included in the project files below.</p>
<p>This tutorial inspired by Blommis. <img src='http://www.sdltutorials.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><b>SDL Image &#8211; Tutorial Files:</b><br />
<b>Win32:</b> <a href="../tutorials/sdl-image.zip">Zip</a>, <a href="../tutorials/sdl-image.rar">Rar</a><br />
<b>Linux:</b> <a href="../tutorials/sdl-image.tar.gz">Tar</a> (Thanks Gaten), <a href="../tutorials/sdl-image-compiled.tar.gz">Binary</a> (Thanks Thomas)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sdltutorials.com/sdl-image/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
	</channel>
</rss>
