<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3716484034095527645</id><updated>2012-01-28T10:54:54.968-08:00</updated><category term='tile'/><category term='editor'/><category term='android'/><category term='sdl_ttf'/><category term='collision detection'/><category term='basic'/><category term='blob wars'/><category term='sound'/><category term='joystick'/><category term='starfield'/><category term='animation'/><category term='controls'/><category term='edgar'/><category term='tutorial'/><category term='sdl'/><category term='map'/><category term='image'/><category term='game'/><category term='starfighter'/><category term='sprite'/><category term='bullet'/><category term='blob and conquer'/><category term='parallel realities'/><title type='text'>Parallel Realities</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-7828169906963540620</id><published>2012-01-11T11:57:00.000-08:00</published><updated>2012-01-11T11:57:02.527-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='edgar'/><title type='text'>The Legend of Edgar 0.96</title><content type='html'>The Legend of Edgar has been updated to 0.96. This release fixes a couple of bugs.&lt;br /&gt;&lt;br /&gt;* Fixed a problem with some level exits not activating (making the Crypt accessible)&lt;br /&gt;* Home directory lookup now more stable on Linux&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sourceforge.net/projects/legendofedgar/" target="_blank"&gt;Download 0.96 from SourceForge&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-yq-aNvVrUXs/TwvwNyNg9uI/AAAAAAAAA0M/a52mEB0ujTg/s1600/edgar38.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-yq-aNvVrUXs/TwvwNyNg9uI/AAAAAAAAA0M/a52mEB0ujTg/s320/edgar38.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-7828169906963540620?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/7828169906963540620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2012/01/legend-of-edgar-096.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/7828169906963540620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/7828169906963540620'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2012/01/legend-of-edgar-096.html' title='The Legend of Edgar 0.96'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-yq-aNvVrUXs/TwvwNyNg9uI/AAAAAAAAA0M/a52mEB0ujTg/s72-c/edgar38.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-2568002060291982053</id><published>2012-01-03T12:53:00.000-08:00</published><updated>2012-01-03T12:53:05.433-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='edgar'/><title type='text'>The Legend of Edgar 0.95</title><content type='html'>The Legend of Edgar has been updated to 0.95. This release features a large number of changes&lt;br /&gt;&lt;br /&gt;* The Crypt is now accessible&lt;br /&gt;* Added a basic title screen&lt;br /&gt;* Fixed more crashes on Windows&lt;br /&gt;* Removed dependency on SDL_Net&lt;br /&gt;* Made one the light pillars in the Catacombs stay active longer&lt;br /&gt;* Raising and lowering the music volume now works correctly&lt;br /&gt;* Fixed a possible hang during the end credits&lt;br /&gt;* Bombs grabbed by the Borer no longer play their sound effect endlessly&lt;br /&gt;* Dud Gazer Eyes no longer float in the air when thrown&lt;br /&gt;* Renamed Continue to Restart Checkpoint&lt;br /&gt;* The Restart Checkpoint option is now disabled after defeating the Watchdog&lt;br /&gt;* Added a new medal: "Completed the game with only 5 hit points"&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt; &lt;td&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-U0ftiGWnEpA/TwIh6-y6mMI/AAAAAAAAAz8/BFtrcveqjk8/s1600/edgar41.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-U0ftiGWnEpA/TwIh6-y6mMI/AAAAAAAAAz8/BFtrcveqjk8/s320/edgar41.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/-sbrk2JYaS5A/TwIh8klt7hI/AAAAAAAAA0E/6Vqj7AoqPuo/s1600/edgar42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-sbrk2JYaS5A/TwIh8klt7hI/AAAAAAAAA0E/6Vqj7AoqPuo/s320/edgar42.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sourceforge.net/projects/legendofedgar/" target="_blank"&gt;Download 0.95 from SourceForge&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-2568002060291982053?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/2568002060291982053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2012/01/legend-of-edgar-095.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/2568002060291982053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/2568002060291982053'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2012/01/legend-of-edgar-095.html' title='The Legend of Edgar 0.95'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-U0ftiGWnEpA/TwIh6-y6mMI/AAAAAAAAAz8/BFtrcveqjk8/s72-c/edgar41.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-5317015311913882982</id><published>2011-11-27T05:09:00.000-08:00</published><updated>2011-11-30T00:34:47.772-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='edgar'/><title type='text'>The Legend of Edgar 0.94</title><content type='html'>The Legend of Edgar has been updated to 0.94. This release fixes a bunch of minor issues:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The crash on Windows has been fixed &lt;/li&gt;&lt;li&gt;Fixed a problem with the ice cubes moving too quickly&lt;/li&gt;&lt;li&gt;Jacob no longer drops infinite swords&lt;/li&gt;&lt;li&gt;The rift summoned by Mataeus no longer plays its sound effect endlessly&lt;/li&gt;&lt;li&gt;Fixed a problem with The Sewer Dweller's attacks being unblockable&lt;/li&gt;&lt;li&gt;Ice cubes now vanish after a few seconds instead of hanging around forever&lt;/li&gt;&lt;li&gt;Dark Summoners no longer get stuck after casting lightning&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="https://sourceforge.net/projects/legendofedgar/" target="_blank"&gt;Download 0.94 from SourceForge&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-5317015311913882982?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/5317015311913882982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/11/legend-of-edgar-094.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/5317015311913882982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/5317015311913882982'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/11/legend-of-edgar-094.html' title='The Legend of Edgar 0.94'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-4789621060460433276</id><published>2011-10-02T06:27:00.000-07:00</published><updated>2011-10-02T06:27:22.961-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='map'/><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='collision detection'/><category scheme='http://www.blogger.com/atom/ns#' term='tile'/><title type='text'>Intermediate Game Tutorial #4 - Tile Based Map Collision Detection</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Intermediate Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Intermediate Game Tutorial #4 - Tile Based Map Collision Detection&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 24pt; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-GO5-763sYuc/ToDaRlj8W3I/AAAAAAAAAzU/68ZRJkFxZs0/s1600/tutorial14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-GO5-763sYuc/ToDaRlj8W3I/AAAAAAAAAzU/68ZRJkFxZs0/s320/tutorial14.png" width="320" /&gt;&lt;/a&gt;&lt;span style="font-size: 14pt;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Collision Detection&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;This tutorial deals with collision detection.&lt;br /&gt;Compile and run tutorial14. The program will read the map data file and display the map on the screen. Use the arrow keys (not the ones on the numeric pad) to move the character around the screen. Pressing space will make the character jump. Should the character fall out of the map screen it will reappear after a couple of seconds.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;We reintroduce the &lt;span class="code"&gt;Entity&lt;/span&gt; structure and add a few extra variables to it: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Entity&lt;br /&gt;{&lt;br /&gt;    int w, h, onGround;&lt;br /&gt;    int thinkTime;&lt;br /&gt;    float x, y, dirX, dirY;&lt;br /&gt;} Entity;&lt;/pre&gt;The &lt;span class="code"&gt;onGround&lt;/span&gt; variable is used to determine if the &lt;span class="code"&gt;Entity&lt;/span&gt; is on the ground. We use this to determine whether or not the &lt;span class="code"&gt;Entity&lt;/span&gt; is allowed to jump or perform any other ground based action. &lt;span class="code"&gt;dirX&lt;/span&gt; and &lt;span class="code"&gt;dirY&lt;/span&gt; are used to apply directional force to the &lt;span class="code"&gt;x&lt;/span&gt; and &lt;span class="code"&gt;y&lt;/span&gt; variables. This is important when working with gravity or friction. We will see how this is used later.    We will only look at three files in this tutorial since the other files and functions have been covered numerous times in previous tutorials. &lt;br /&gt;&lt;span class="code"&gt;map.c&lt;/span&gt; contains an extra function to center an &lt;span class="code"&gt;Entity&lt;/span&gt; on the screen: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void centerEntityOnMap(Entity *e)&lt;br /&gt;{&lt;br /&gt;    map.startX = e-&amp;gt;x - (SCREEN_WIDTH / 2);&lt;br /&gt;    &lt;br /&gt;    if (map.startX &amp;lt; 0)&lt;br /&gt;    {&lt;br /&gt;        map.startX = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (map.startX + SCREEN_WIDTH &amp;gt;= map.maxX)&lt;br /&gt;    {&lt;br /&gt;        map.startX = map.maxX - SCREEN_WIDTH;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    map.startY = e-&amp;gt;y - (SCREEN_HEIGHT / 2);&lt;br /&gt;    &lt;br /&gt;    if (map.startY &amp;lt; 0)&lt;br /&gt;    {&lt;br /&gt;        map.startY = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (map.startY + SCREEN_HEIGHT &amp;gt;= map.maxY)&lt;br /&gt;    {&lt;br /&gt;        map.startY = map.maxY - SCREEN_HEIGHT;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;We take the &lt;span class="code"&gt;Entity&lt;/span&gt;'s current horizontal position, subtract half the screen's width from it and assign this to &lt;span class="code"&gt;startX&lt;/span&gt;. We then perform the usual bounds check to make sure that the &lt;span class="code"&gt;startX&lt;/span&gt; value to make sure we don't attempt to draw non existant parts of the map. We do the same with the vertical position.   We will now look at the code to handle the player, which is in &lt;span class="code"&gt;player.c&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doPlayer()&lt;br /&gt;{&lt;br /&gt;    if (player.thinkTime == 0)&lt;br /&gt;    {&lt;br /&gt;        player.dirX = 0;&lt;br /&gt;    &lt;br /&gt;        /* Gravity always pulls the player down */&lt;br /&gt;    &lt;br /&gt;        player.dirY += GRAVITY_SPEED;&lt;br /&gt;        &lt;br /&gt;        if (player.dirY &amp;gt;= MAX_FALL_SPEED)&lt;br /&gt;        {&lt;br /&gt;            player.dirY = MAX_FALL_SPEED;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (input.left == 1)&lt;br /&gt;        {&lt;br /&gt;            player.dirX -= PLAYER_SPEED;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        else if (input.right == 1)&lt;br /&gt;        {&lt;br /&gt;            player.dirX += PLAYER_SPEED;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (input.jump == 1)&lt;br /&gt;        {&lt;br /&gt;            if (player.onGround == 1)&lt;br /&gt;            {&lt;br /&gt;                player.dirY = -11;&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            input.jump = 0;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        checkToMap(&amp;amp;player);&lt;br /&gt;        &lt;br /&gt;        centerEntityOnMap(&amp;amp;player);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (player.thinkTime &amp;gt; 0)&lt;br /&gt;    {&lt;br /&gt;        player.thinkTime--;&lt;br /&gt;        &lt;br /&gt;        if (player.thinkTime == 0)&lt;br /&gt;        {&lt;br /&gt;            initPlayer();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The first check we perform is that the player's &lt;span class="code"&gt;thinkTime&lt;/span&gt; is greater than 0 and if it is then we can perform actions on it. We first set the &lt;span class="code"&gt;dirX&lt;/span&gt; to 0. This means that the player will stop moving instantly when we release the key. If we wanted to make the player slowly stop then we could do something like the following: &lt;pre class="cpp" name="code"&gt;player.dirX *= 0.98;&lt;/pre&gt;This would mean that when we released the arrow key the player would take a few frames to come to a complete halt. This could be used to give the illusion that the player is on ice where there is a low coefficient of friction. Next we apply gravity to the player's vertical movement. Not that we do not simply set the &lt;span class="code"&gt;dirY&lt;/span&gt; to the amount of gravitational pull, but we increment it instead. This will mean that anything currently moving up will start to be pulled down after a while. We also limit the maximum speed at which the player will fall. The left and right movements should be self explanitory. When &lt;span class="code"&gt;jump&lt;/span&gt; is detected we need to first check if the player is on the ground, otherwise they could jump any time they wanted, which is undesirable. Provided they can jump, we set the &lt;span class="code"&gt;dirY&lt;/span&gt; to -11, which in this game is a reasonable amount to jump by. Note that this value will be decremented by gravity in the following frames. Finally, we call &lt;span class="code"&gt;checkToMap&lt;/span&gt; and &lt;span class="code"&gt;centerEntityOnMap&lt;/span&gt;. We will look at &lt;span class="code"&gt;checkToMap&lt;/span&gt; shortly. If the player's &lt;span class="code"&gt;thinkTime&lt;/span&gt; is greater than 0 then the player cannot perform any actions and we simply decrease the value. Once it hits 0 we call &lt;span class="code"&gt;initPlayer&lt;/span&gt; to reset the player on the map.    We will now look at the map collision detection. This function is stored in &lt;span class="code"&gt;collisions.c&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void checkToMap(Entity *e)&lt;br /&gt;{&lt;br /&gt;    int i, x1, x2, y1, y2;&lt;br /&gt;    &lt;br /&gt;    /* Remove the user from the ground */&lt;br /&gt;    &lt;br /&gt;    e-&amp;gt;onGround = 0;&lt;br /&gt;    &lt;br /&gt;    /* Test the horizontal movement first */&lt;br /&gt;    &lt;br /&gt;    i = e-&amp;gt;h &amp;gt; TILE_SIZE ? TILE_SIZE : e-&amp;gt;h;&lt;br /&gt;    &lt;br /&gt;    for (;;)&lt;br /&gt;    {&lt;br /&gt;        x1 = (e-&amp;gt;x + e-&amp;gt;dirX) / TILE_SIZE;&lt;br /&gt;        x2 = (e-&amp;gt;x + e-&amp;gt;dirX + e-&amp;gt;w - 1) / TILE_SIZE;&lt;br /&gt;    &lt;br /&gt;        y1 = (e-&amp;gt;y) / TILE_SIZE;&lt;br /&gt;        y2 = (e-&amp;gt;y + i - 1) / TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;        if (x1 &amp;gt;= 0 &amp;amp;&amp;amp; x2 &amp;lt; MAX_MAP_X &amp;amp;&amp;amp; y1 &amp;gt;= 0 &amp;amp;&amp;amp; y2 &amp;lt; MAX_MAP_Y)&lt;br /&gt;        {&lt;br /&gt;            if (e-&amp;gt;dirX &amp;gt; 0)&lt;br /&gt;            {&lt;br /&gt;                /* Trying to move right */&lt;br /&gt;        &lt;br /&gt;                if ((map.tile[y1][x2] != BLANK_TILE) || (map.tile[y2][x2]!=BLANK_TILE))&lt;br /&gt;                {&lt;br /&gt;                    /* Place the player as close to the solid tile as possible */&lt;br /&gt;        &lt;br /&gt;                    e-&amp;gt;x = x2 * TILE_SIZE;&lt;br /&gt;                    &lt;br /&gt;                    e-&amp;gt;x -= e-&amp;gt;w + 1;&lt;br /&gt;        &lt;br /&gt;                    e-&amp;gt;dirX = 0;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        &lt;br /&gt;            else if (e-&amp;gt;dirX &amp;lt; 0)&lt;br /&gt;            {&lt;br /&gt;                /* Trying to move left */&lt;br /&gt;        &lt;br /&gt;                if ((map.tile[y1][x1] != BLANK_TILE) || (map.tile[y2][x1]!=BLANK_TILE))&lt;br /&gt;                {&lt;br /&gt;                    /* Place the player as close to the solid tile as possible */&lt;br /&gt;                    &lt;br /&gt;                    e-&amp;gt;x = (x1 + 1) * TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;                    e-&amp;gt;dirX = 0;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (i == e-&amp;gt;h)&lt;br /&gt;        {&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        i += TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;        if (i &amp;gt; e-&amp;gt;h)&lt;br /&gt;        {&lt;br /&gt;            i = e-&amp;gt;h;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Now test the vertical movement */&lt;br /&gt;    &lt;br /&gt;    i = e-&amp;gt;w &amp;gt; TILE_SIZE ? TILE_SIZE : e-&amp;gt;w;&lt;br /&gt;    &lt;br /&gt;    for (;;)&lt;br /&gt;    {&lt;br /&gt;        x1 = (e-&amp;gt;x) / TILE_SIZE;&lt;br /&gt;        x2 = (e-&amp;gt;x + i) / TILE_SIZE;&lt;br /&gt;    &lt;br /&gt;        y1 = (e-&amp;gt;y + e-&amp;gt;dirY) / TILE_SIZE;&lt;br /&gt;        y2 = (e-&amp;gt;y + e-&amp;gt;dirY + e-&amp;gt;h) / TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;        if (x1 &amp;gt;= 0 &amp;amp;&amp;amp; x2 &amp;lt; MAX_MAP_X &amp;amp;&amp;amp; y1 &amp;gt;= 0 &amp;amp;&amp;amp; y2 &amp;lt; MAX_MAP_Y)&lt;br /&gt;        {&lt;br /&gt;            if (e-&amp;gt;dirY &amp;gt; 0)&lt;br /&gt;            {&lt;br /&gt;                /* Trying to move down */&lt;br /&gt;                &lt;br /&gt;                if ((map.tile[y2][x1] != BLANK_TILE) || (map.tile[y2][x2]!=BLANK_TILE))&lt;br /&gt;                {&lt;br /&gt;                    /* Place the player as close to the solid tile as possible */&lt;br /&gt;                    &lt;br /&gt;                    e-&amp;gt;y = y2 * TILE_SIZE;&lt;br /&gt;                    e-&amp;gt;y -= e-&amp;gt;h;&lt;br /&gt;        &lt;br /&gt;                    e-&amp;gt;dirY = 0;&lt;br /&gt;                    &lt;br /&gt;                    e-&amp;gt;onGround = 1;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        &lt;br /&gt;            else if (e-&amp;gt;dirY &amp;lt; 0)&lt;br /&gt;            {&lt;br /&gt;                /* Trying to move up */&lt;br /&gt;        &lt;br /&gt;                if ((map.tile[y1][x1] != BLANK_TILE) || (map.tile[y1][x2]!=BLANK_TILE))&lt;br /&gt;                {&lt;br /&gt;                    /* Place the player as close to the solid tile as possible */&lt;br /&gt;        &lt;br /&gt;                    e-&amp;gt;y = (y1 + 1) * TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;                    e-&amp;gt;dirY = 0;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (i == e-&amp;gt;w)&lt;br /&gt;        {&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        i += TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;        if (i &amp;gt; e-&amp;gt;w)&lt;br /&gt;        {&lt;br /&gt;            i = e-&amp;gt;w;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Now apply the movement */&lt;br /&gt;&lt;br /&gt;    e-&amp;gt;x += e-&amp;gt;dirX;&lt;br /&gt;    e-&amp;gt;y += e-&amp;gt;dirY;&lt;br /&gt;    &lt;br /&gt;    if (e-&amp;gt;x &amp;lt; 0)&lt;br /&gt;    {&lt;br /&gt;        e-&amp;gt;x = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (e-&amp;gt;x + e-&amp;gt;w &amp;gt;= map.maxX)&lt;br /&gt;    {&lt;br /&gt;        e-&amp;gt;x = map.maxX - e-&amp;gt;w - 1;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (e-&amp;gt;y &amp;gt; map.maxY)&lt;br /&gt;    {&lt;br /&gt;        e-&amp;gt;thinkTime = 60;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;This function is fairly complex, so we will look at it in sections. Firstly, we set the &lt;span class="code"&gt;onGround&lt;/span&gt; variable to 0. During our map tests we may set this variable back to 1. The easiest way to test map collisions is to check the horizontal and vertical movements separately. We will start with the horizontal movement. Determining whether or not an &lt;span class="code"&gt;Entity&lt;/span&gt; has collided with a map block is a case of checking the value of the map tile that each of the 4 corners of the &lt;span class="code"&gt;Entity&lt;/span&gt; will be in after the movement has taken place. This approach will only work though if the &lt;span class="code"&gt;Entity&lt;/span&gt;'s horizontal and vertical sizes are less than or equal to the &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt;, otherwise a very large &lt;span class="code"&gt;Entity&lt;/span&gt; will be able to move through the map tiles since its corners may not necessarily collide with a tile even though its midsection does. To get around this problem we will break the &lt;span class="code"&gt;Entity&lt;/span&gt;'s height into portions: &lt;pre class="cpp" name="code"&gt;i = e-&amp;gt;h &amp;gt; TILE_SIZE ? TILE_SIZE : e-&amp;gt;h;&lt;/pre&gt;In our example, the player sprite is 55 pixels tall, &lt;span class="code"&gt;i&lt;/span&gt; will initially be &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt;. We next enter a loop and calculate the corners that the player will be in after it has moved: &lt;pre class="cpp" name="code"&gt;x1 = (e-&amp;gt;x + e-&amp;gt;dirX) / TILE_SIZE;&lt;br /&gt;x2 = (e-&amp;gt;x + e-&amp;gt;dirX + e-&amp;gt;w - 1) / TILE_SIZE;&lt;br /&gt;&lt;br /&gt;y1 = (e-&amp;gt;y) / TILE_SIZE;&lt;br /&gt;y2 = (e-&amp;gt;y + i - 1) / TILE_SIZE;&lt;/pre&gt;&lt;span class="code"&gt;x1&lt;/span&gt; is the left side, &lt;span class="code"&gt;x2&lt;/span&gt; is the right side, &lt;span class="code"&gt;y1&lt;/span&gt; is the top side and &lt;span class="code"&gt;y2&lt;/span&gt; is the bottom. We will combine these values together to calculate the coordinates of the corners. Next we check that the values the 4 sides are within the bounds of the tile array. If they are not then we skip over the calculation since the player has gone outside the bounds of the screen, either because they have jumped at the top of the screen or they may have fallen out of the map, and we don't want to attempt to index an array outside of its bounds. Provided the values are legal we then check if the player is moving right: &lt;pre class="cpp" name="code"&gt;if (e-&amp;gt;dirX &amp;gt; 0)&lt;br /&gt;{&lt;br /&gt;    /* Trying to move right */&lt;br /&gt;&lt;br /&gt;    if ((map.tile[y1][x2] != BLANK_TILE) || (map.tile[y2][x2] != BLANK_TILE))&lt;br /&gt;    {&lt;br /&gt;        /* Place the player as close to the solid tile as possible */&lt;br /&gt;&lt;br /&gt;        e-&amp;gt;x = x2 * TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;        e-&amp;gt;x -= e-&amp;gt;w + 1;&lt;br /&gt;&lt;br /&gt;        e-&amp;gt;dirX = 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;We want to check the top right and bottom right corners of the &lt;span class="code"&gt;Entity&lt;/span&gt; so we use &lt;span class="code"&gt;y1&lt;/span&gt; and &lt;span class="code"&gt;y2&lt;/span&gt; for the top and bottom values and &lt;span class="code"&gt;x2&lt;/span&gt; since it is the right side of the &lt;span class="code"&gt;Entity&lt;/span&gt;. We then check the tile type at these two corners and if either of the tiles is not empty, then we have hit a map tile. We then move the &lt;span class="code"&gt;Entity&lt;/span&gt; as close to the tile as possible and set the &lt;span class="code"&gt;dirX&lt;/span&gt; to 0. If we are moving left then the code is fairly similar: &lt;pre class="cpp" name="code"&gt;else if (e-&amp;gt;dirX &amp;lt; 0)&lt;br /&gt;{&lt;br /&gt;    /* Trying to move left */&lt;br /&gt;&lt;br /&gt;    if ((map.tile[y1][x1] != BLANK_TILE) || (map.tile[y2][x1] != BLANK_TILE))&lt;br /&gt;    {&lt;br /&gt;        /* Place the player as close to the solid tile as possible */&lt;br /&gt;        &lt;br /&gt;        e-&amp;gt;x = (x1 + 1) * TILE_SIZE;&lt;br /&gt;&lt;br /&gt;        e-&amp;gt;dirX = 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;We still use &lt;span class="code"&gt;y1&lt;/span&gt; and &lt;span class="code"&gt;y2&lt;/span&gt; but we use &lt;span class="code"&gt;x1&lt;/span&gt; since this is the left side of the &lt;span class="code"&gt;Entity&lt;/span&gt;. Next we check if we have to test the next block of the body. &lt;pre class="cpp" name="code"&gt;/* Exit this loop if we have tested all of the body */&lt;br /&gt;&lt;br /&gt;if (i == e-&amp;gt;h)&lt;br /&gt;{&lt;br /&gt;    break;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Test the next block */&lt;br /&gt;&lt;br /&gt;i += TILE_SIZE;&lt;br /&gt;&lt;br /&gt;if (i &amp;gt; e-&amp;gt;h)&lt;br /&gt;{&lt;br /&gt;    i = e-&amp;gt;h;&lt;br /&gt;}&lt;/pre&gt;If the current value of &lt;span class="code"&gt;i&lt;/span&gt; is equal to the &lt;span class="code"&gt;Entity&lt;/span&gt;'s height then we have completed testing the horizontal movement and can exit the loop. Otherwise we increment &lt;span class="code"&gt;i&lt;/span&gt; by &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt; to test the next block. If &lt;span class="code"&gt;i&lt;/span&gt; is greater than the &lt;span class="code"&gt;Entity&lt;/span&gt;'s height then we set it to the &lt;span class="code"&gt;Entity&lt;/span&gt;'s height since we don't want to test outside of this. We then test the vertical movement, which is similar to the horizontal checking, except that during the vertical checking, if we are moving down and we encounter a solid tile, we set the &lt;span class="code"&gt;onGround&lt;/span&gt; variable to 1. Finally, we apply the &lt;span class="code"&gt;dirX&lt;/span&gt; and &lt;span class="code"&gt;dirY&lt;/span&gt; to allow the &lt;span class="code"&gt;Entity&lt;/span&gt; to move: &lt;pre class="cpp" name="code"&gt;/* Now apply the movement */&lt;br /&gt;&lt;br /&gt;e-&amp;gt;x += e-&amp;gt;dirX;&lt;br /&gt;e-&amp;gt;y += e-&amp;gt;dirY;&lt;br /&gt;&lt;br /&gt;if (e-&amp;gt;x &amp;lt; 0)&lt;br /&gt;{&lt;br /&gt;    e-&amp;gt;x = 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;else if (e-&amp;gt;x + e-&amp;gt;w &amp;gt;= map.maxX)&lt;br /&gt;{&lt;br /&gt;    e-&amp;gt;x = map.maxX - e-&amp;gt;w - 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if (e-&amp;gt;y &amp;gt; map.maxY)&lt;br /&gt;{&lt;br /&gt;    e-&amp;gt;thinkTime = 60;&lt;br /&gt;}&lt;/pre&gt;Note that &lt;span class="code"&gt;dirX&lt;/span&gt; and &lt;span class="code"&gt;dirY&lt;/span&gt; may have been set to 0 in which case no movement will take place. We also prevent the player from being able to move off the left and right hand edges of the map. If the player's &lt;span class="code"&gt;y&lt;/span&gt; variable is greater than the &lt;span class="code"&gt;maxY&lt;/span&gt; of the map then the &lt;span class="code"&gt;Entity&lt;/span&gt; has fallen out of the map, in which case we set the &lt;span class="code"&gt;Entity&lt;/span&gt;'s &lt;span class="code"&gt;thinkTime&lt;/span&gt; to 60, which is about 1 second. As seen earlier, this will make the player reappear at the start of the map.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;The code for checking the map may seem very long, but in reality we are simply performing the same check 4 times, one for each corner. You can use the map editor in the previous tutorial to modify the map included in this tutorial. In the following tutorials we will look at more animation and additions to the map.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial14.tar.gz/download"&gt;tutorial14.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-4789621060460433276?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/4789621060460433276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-4-tile-based.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4789621060460433276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4789621060460433276'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-4-tile-based.html' title='Intermediate Game Tutorial #4 - Tile Based Map Collision Detection'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-GO5-763sYuc/ToDaRlj8W3I/AAAAAAAAAzU/68ZRJkFxZs0/s72-c/tutorial14.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-8429977378032962943</id><published>2011-10-02T06:22:00.000-07:00</published><updated>2011-10-02T06:28:01.380-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='map'/><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='editor'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='tile'/><title type='text'>Intermediate Game Tutorial #3 - A Tile Based Map Editor</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Intermediate Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Intermediate Game Tutorial #3 - A Tile Based Map Editor&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-yfhSg08lNUU/ToDaRPGi7XI/AAAAAAAAAzQ/irRnm0VcAfk/s1600/tutorial13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-yfhSg08lNUU/ToDaRPGi7XI/AAAAAAAAAzQ/irRnm0VcAfk/s320/tutorial13.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;The Map Editor&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;In this tutorial we will create a basic map editor&lt;br /&gt;Compile and run tutorial13. The program will read the map data file and display the map on the screen. Use the arrow keys (not the ones on the numeric pad) to scroll the map around. Moving the mouse cursor will move the tile block around. Clicking the left mouse button or pressing space will place a tile at the current mouse position. Clicking the right mouse button will blank the tile at the current map position. Pressing the comma or minus key (not the one on the numeric pad) will select the previous map tile. Pressing the period or plus key (not the one on the numeric pad) will select the next map tile. Pressing S will save the map data and pressing L will load the map data.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;We have increased the maximum number of tiles to 400 x 300 and also updated the &lt;span class="code"&gt;Map&lt;/span&gt; structure: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Map&lt;br /&gt;{&lt;br /&gt;    char *filename;&lt;br /&gt;    int startX, startY;&lt;br /&gt;    int maxX, maxY;&lt;br /&gt;    int tile[MAX_MAP_Y][MAX_MAP_X];&lt;br /&gt;    SDL_Surface *background;&lt;br /&gt;} Map;&lt;/pre&gt;The &lt;span class="code"&gt;filename&lt;/span&gt; variable simply stores the path to the map data so that we can load and save it. The &lt;span class="code"&gt;background&lt;/span&gt; variable is the background image. Currently this is hardcoded but later tutorials will see the filename stored as part of the map data. We also create a structure to handle the tile cursor as follows: &lt;pre class="cpp" name="code"&gt;typedef struct Cursor&lt;br /&gt;{&lt;br /&gt;    int x, y, tileID;&lt;br /&gt;} Cursor;&lt;/pre&gt;The &lt;span class="code"&gt;x&lt;/span&gt; and &lt;span class="code"&gt;y&lt;/span&gt; variables are screen coordinates and the &lt;span class="code"&gt;tileID&lt;/span&gt; is the current ID of the selected tile. We also have a message structure &lt;pre class="cpp" name="code"&gt;typedef struct Message&lt;br /&gt;{&lt;br /&gt;    char text[MAX_MESSAGE_LENGTH];&lt;br /&gt;    int counter;&lt;br /&gt;} Message;&lt;/pre&gt;This structure is used to display messages on the screen. The message will be displayed on the screen as long as the counter is greater than 0.    The map loading code in &lt;span class="code"&gt;map.c&lt;/span&gt; has changed to allow dynamic setting of the maximum horizontal and vertical scrolling: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void loadMap(char *name)&lt;br /&gt;{&lt;br /&gt;    int x, y;&lt;br /&gt;    FILE *fp;&lt;br /&gt;&lt;br /&gt;    fp = fopen(name, "rb");&lt;br /&gt;&lt;br /&gt;    /* If we can't open the map then exit */&lt;br /&gt;&lt;br /&gt;    if (fp == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Failed to open map %s\n", name);&lt;br /&gt;&lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Read the data from the file into the map */&lt;br /&gt;    &lt;br /&gt;    map.maxX = map.maxY = 0;&lt;br /&gt;&lt;br /&gt;    for (y=0;y&amp;lt;MAX_MAP_Y;y++)&lt;br /&gt;    {&lt;br /&gt;        for (x=0;x&amp;lt;MAX_MAP_X;x++)&lt;br /&gt;        {&lt;br /&gt;            fscanf(fp, "%d", &amp;amp;map.tile[y][x]);&lt;br /&gt;            &lt;br /&gt;            if (map.tile[y][x] != BLANK_TILE)&lt;br /&gt;            {&lt;br /&gt;                if (x &amp;gt; map.maxX)&lt;br /&gt;                {&lt;br /&gt;                    map.maxX = x;&lt;br /&gt;                }&lt;br /&gt;                &lt;br /&gt;                if (y &amp;gt; map.maxY)&lt;br /&gt;                {&lt;br /&gt;                    map.maxY = y;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    map.maxX++;&lt;br /&gt;    map.maxY++;&lt;br /&gt;    &lt;br /&gt;    /* Set the start coordinates */&lt;br /&gt;    &lt;br /&gt;    map.startX = map.startY = 0;&lt;br /&gt;    &lt;br /&gt;    /* Set the maximum scroll position of the map */&lt;br /&gt;    &lt;br /&gt;    map.maxX = MAX_MAP_X * TILE_SIZE;&lt;br /&gt;    map.maxY = MAX_MAP_Y * TILE_SIZE;&lt;br /&gt;    &lt;br /&gt;    /* Set the filename */&lt;br /&gt;    &lt;br /&gt;    map.filename = name;&lt;br /&gt;&lt;br /&gt;    /* Close the file afterwards */&lt;br /&gt;&lt;br /&gt;    fclose(fp);&lt;br /&gt;}&lt;/pre&gt;Before reading the map data, we set the &lt;span class="code"&gt;maxX&lt;/span&gt; and &lt;span class="code"&gt;maxY&lt;/span&gt; values to 0 and then, while reading the map data, we check if the current map value is not the blank tile. If this is true then we check if the current &lt;span class="code"&gt;x&lt;/span&gt; value is greater than the current &lt;span class="code"&gt;maxX&lt;/span&gt; value and if it is, then we set it to &lt;span class="code"&gt;x&lt;/span&gt;. We apply the same logic to the &lt;span class="code"&gt;maxY&lt;/span&gt; variable. Since this is a map editor however, limiting the scrolling to the bounds of the size of the map would not allow us to expand the map so, we set the size of the map to the maximum possible size. In the next tutorial we will not perform this step. Finally, we set the filename of the map. The save map code is similar in places: &lt;pre class="cpp" name="code"&gt;void saveMap()&lt;br /&gt;{&lt;br /&gt;    int x, y;&lt;br /&gt;    FILE *fp;&lt;br /&gt;&lt;br /&gt;    fp = fopen(map.filename, "wb");&lt;br /&gt;&lt;br /&gt;    /* If we can't open the map then exit */&lt;br /&gt;&lt;br /&gt;    if (fp == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Failed to open map %s\n", map.filename);&lt;br /&gt;&lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Write the data from the file into the map */&lt;br /&gt;&lt;br /&gt;    for (y=0;y&amp;lt;MAX_MAP_Y;y++)&lt;br /&gt;    {&lt;br /&gt;        for (x=0;x&amp;lt;MAX_MAP_X;x++)&lt;br /&gt;        {&lt;br /&gt;            fprintf(fp, "%d ", map.tile[y][x]);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        fprintf(fp, "\n");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Close the file afterwards */&lt;br /&gt;&lt;br /&gt;    fclose(fp);&lt;br /&gt;}&lt;/pre&gt;First we open the file that the map was loaded from, then we loop through the map from processesing each row and column and writing each map value to the file. We also terminate each row with a carriage return which will improve readability if we need to open the map in a text editor. Also in this file is the &lt;span class="code"&gt;loadMapTiles&lt;/span&gt; function: &lt;pre class="cpp" name="code"&gt;void loadMapTiles()&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;    char filename[40];&lt;br /&gt;    FILE *fp;&lt;br /&gt;    &lt;br /&gt;    for (i=0;i&amp;lt;MAX_TILES;i++)&lt;br /&gt;    {&lt;br /&gt;        sprintf(filename, "gfx/map/%d.png", i);&lt;br /&gt;        &lt;br /&gt;        fp = fopen(filename, "rb");&lt;br /&gt;        &lt;br /&gt;        if (fp == NULL)&lt;br /&gt;        {&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        fclose(fp);&lt;br /&gt;        &lt;br /&gt;        mapImages[i] = loadImage(filename);&lt;br /&gt;        &lt;br /&gt;        if (mapImages[i] == NULL)&lt;br /&gt;        {&lt;br /&gt;            exit(1);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Since we have multiple map tiles now, the easiest way to load them all is to give each file an id number, starting with 0 for the blank tile and incrementing the number for each subsequent file. We check that the file exists for the id number we are trying to load and if it does then we load it. The &lt;span class="code"&gt;freeMapTiles&lt;/span&gt; function is a standard loop that frees our images so we will skip over it.    In &lt;span class="code"&gt;input.c&lt;/span&gt;, we add the ability to read the mouse buttons as follows: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;case SDL_MOUSEBUTTONDOWN:&lt;br /&gt;    switch(event.button.button)&lt;br /&gt;    {&lt;br /&gt;        case SDL_BUTTON_LEFT:&lt;br /&gt;            input.add = 1;&lt;br /&gt;        break;&lt;br /&gt;        &lt;br /&gt;        case SDL_BUTTON_RIGHT:&lt;br /&gt;            input.remove = 1;&lt;br /&gt;        break;&lt;br /&gt;        &lt;br /&gt;        default:&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;break;&lt;br /&gt;&lt;br /&gt;case SDL_MOUSEBUTTONUP:&lt;br /&gt;    switch(event.button.button)&lt;br /&gt;    {&lt;br /&gt;        case SDL_BUTTON_LEFT:&lt;br /&gt;            input.add = 0;&lt;br /&gt;        break;&lt;br /&gt;        &lt;br /&gt;        case SDL_BUTTON_RIGHT:&lt;br /&gt;            input.remove = 0;&lt;br /&gt;        break;&lt;br /&gt;        &lt;br /&gt;        default:&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;break;&lt;/pre&gt;The code should be self explainitory as it is very similar to reading key presses. We also read in the position of the mouse cursor: &lt;pre class="cpp" name="code"&gt;/* Get the mouse coordinates */&lt;br /&gt;&lt;br /&gt;SDL_GetMouseState(&amp;amp;input.mouseX, &amp;amp;input.mouseY);&lt;br /&gt;&lt;br /&gt;input.mouseX /= TILE_SIZE;&lt;br /&gt;input.mouseY /= TILE_SIZE;&lt;br /&gt;&lt;br /&gt;input.mouseX *= TILE_SIZE;&lt;br /&gt;input.mouseY *= TILE_SIZE;&lt;/pre&gt;&lt;span class="code"&gt;SDL_GetMouseState&lt;/span&gt; sets the x and y mouse coordinates to the passed in variables. The x and y coordinates are relative to the SDL window and also does not include the window decoration. We also want to snap the coordinates to a grid. This simply requires dividing the &lt;span class="code"&gt;mouseX&lt;/span&gt; by the &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt; and multiplying it back up again. Since &lt;span class="code"&gt;mouseX&lt;/span&gt; is an integer, we will not get any decimal part when we divide the value.    &lt;span class="code"&gt;cursor.c&lt;/span&gt; contains the functions for manipulating the on screen cursor: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doCursor()&lt;br /&gt;{&lt;br /&gt;    cursor.x = input.mouseX;&lt;br /&gt;    cursor.y = input.mouseY;&lt;br /&gt;    &lt;br /&gt;    if (cursor.y &amp;gt;= SCREEN_HEIGHT - TILE_SIZE)&lt;br /&gt;    {&lt;br /&gt;        cursor.y = SCREEN_HEIGHT - TILE_SIZE * 2;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (input.left == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startX -= TILE_SIZE;&lt;br /&gt;&lt;br /&gt;        if (map.startX &amp;lt; 0)&lt;br /&gt;        {&lt;br /&gt;            map.startX = 0;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (input.right == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startX += TILE_SIZE;&lt;br /&gt;&lt;br /&gt;        if (map.startX + SCREEN_WIDTH &amp;gt;= map.maxX)&lt;br /&gt;        {&lt;br /&gt;            map.startX = map.maxX - SCREEN_WIDTH;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.up == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startY -= TILE_SIZE;&lt;br /&gt;&lt;br /&gt;        if (map.startY &amp;lt; 0)&lt;br /&gt;        {&lt;br /&gt;            map.startY = 0;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (input.down == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startY += TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;        if (map.startY + SCREEN_HEIGHT &amp;gt;= map.maxY)&lt;br /&gt;        {&lt;br /&gt;            map.startY = map.maxY - SCREEN_HEIGHT;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.add == 1)&lt;br /&gt;    {&lt;br /&gt;        map.tile[(map.startY + cursor.y) / TILE_SIZE]&lt;br /&gt;        [(map.startX + cursor.x) / TILE_SIZE] = cursor.tileID;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (input.remove == 1)&lt;br /&gt;    {&lt;br /&gt;        map.tile[(map.startY + cursor.y) / TILE_SIZE]&lt;br /&gt;        [(map.startX + cursor.x) / TILE_SIZE] = BLANK_TILE;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.previous == 1)&lt;br /&gt;    {&lt;br /&gt;        do&lt;br /&gt;        {&lt;br /&gt;            cursor.tileID--;&lt;br /&gt;            &lt;br /&gt;            if (cursor.tileID &amp;lt; 0)&lt;br /&gt;            {&lt;br /&gt;                cursor.tileID = MAX_TILES - 1;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        while (mapImages[cursor.tileID] == NULL);&lt;br /&gt;        &lt;br /&gt;        input.previous = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.next == 1)&lt;br /&gt;    {&lt;br /&gt;        do&lt;br /&gt;        {&lt;br /&gt;            cursor.tileID++;&lt;br /&gt;            &lt;br /&gt;            if (cursor.tileID &amp;gt;= MAX_TILES)&lt;br /&gt;            {&lt;br /&gt;                cursor.tileID = 0;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        while (mapImages[cursor.tileID] == NULL);&lt;br /&gt;        &lt;br /&gt;        input.next = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.save == 1)&lt;br /&gt;    {&lt;br /&gt;        saveMap();&lt;br /&gt;        &lt;br /&gt;        setStatusMessage("Saved OK");&lt;br /&gt;        &lt;br /&gt;        input.save = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.load == 1)&lt;br /&gt;    {&lt;br /&gt;        loadMap(map.filename);&lt;br /&gt;        &lt;br /&gt;        setStatusMessage("Loaded OK");&lt;br /&gt;        &lt;br /&gt;        input.load = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.left == 1 || input.right == 1 || input.up == 1 || input.down == 1)&lt;br /&gt;    {&lt;br /&gt;        SDL_Delay(30);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;First, we prevent the cursor from being able to move into the bottom row of the screen, since we will use that to display messages. We then handle the left, right, up and down arrow key presses as per the previous tutorial. When the &lt;span class="code"&gt;add&lt;/span&gt; input is 1, we place a tile at the current screen and mouse cursor position. We do this by taking the &lt;span class="code"&gt;startX&lt;/span&gt; value and adding the &lt;span class="code"&gt;cursor.x&lt;/span&gt; value and then dividing this value by &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt; to give us the nearest tile. We do the same for the vertical coordinate. We then set this tile value to the &lt;span class="code"&gt;tileID&lt;/span&gt; of the cursor. The &lt;span class="code"&gt;remove&lt;/span&gt; input does the same thing, except that it always sets the tile's value to &lt;span class="code"&gt;BLANK_TILE&lt;/span&gt;. When the &lt;span class="code"&gt;next&lt;/span&gt; input is set, we increment the cursor's &lt;span class="code"&gt;tileID&lt;/span&gt;. If the image referenced by the &lt;span class="code"&gt;tileID&lt;/span&gt; is NULL, we move to the next tile and continue to do so until we encounter a tile that is not NULL. We also wrap the &lt;span class="code"&gt;tileID&lt;/span&gt; value around if it is greater than or equal to &lt;span class="code"&gt;MAX_TILES&lt;/span&gt;. The &lt;span class="code"&gt;previous&lt;/span&gt; input behaves in the same way, except that we decrement the &lt;span class="code"&gt;tileID&lt;/span&gt; instead. If the &lt;span class="code"&gt;save&lt;/span&gt; input is 1 then we call &lt;span class="code"&gt;saveMap&lt;/span&gt; followed by &lt;span class="code"&gt;setStatusMessage&lt;/span&gt;. We will look at this function later. We preform a similar process when &lt;span class="code"&gt;load&lt;/span&gt; is set to 1, except we call &lt;span class="code"&gt;loadMap&lt;/span&gt;. Finally, if any of our navigation inputs are true, then we call &lt;span class="code"&gt;SDL_Delay&lt;/span&gt; to prevent the map from scrolling too fast. Also in this file is the function to draw the cursor. This draws the image referenced by the &lt;span class="code"&gt;tileID&lt;/span&gt;.    The status panel code in &lt;span class="code"&gt;status.c&lt;/span&gt; contains 3 functions: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doStatusPanel()&lt;br /&gt;{&lt;br /&gt;    message.counter--;&lt;br /&gt;    &lt;br /&gt;    if (message.counter &amp;lt;= 0)&lt;br /&gt;    {&lt;br /&gt;        message.counter = 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;doStatusPanel&lt;/span&gt; decrements the message's counter. This is very similar to the &lt;span class="code"&gt;thinkTime&lt;/span&gt; variable seen in earlier tutorials. &lt;pre class="cpp" name="code"&gt;void drawStatusPanel()&lt;br /&gt;{&lt;br /&gt;    SDL_Rect dest;&lt;br /&gt;&lt;br /&gt;    dest.x = 0;&lt;br /&gt;    dest.y = SCREEN_HEIGHT - TILE_SIZE;&lt;br /&gt;    dest.w = SCREEN_WIDTH;&lt;br /&gt;    dest.h = TILE_SIZE;&lt;br /&gt;    &lt;br /&gt;    SDL_FillRect(screen, &amp;amp;dest, 0);&lt;br /&gt;    &lt;br /&gt;    if (message.counter &amp;gt; 0)&lt;br /&gt;    {&lt;br /&gt;        drawString(message.text, 0, SCREEN_HEIGHT - TILE_SIZE, font, 1, 0);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The &lt;span class="code"&gt;drawStatusPanel&lt;/span&gt; function uses a lot of function calls seen in previous tutorials. Firstly we fill the bottom row of the map in black and then, if the message counter is greater than 0, we print the text stored in the message structure. Finally, &lt;pre class="cpp" name="code"&gt;void setStatusMessage(char *text)&lt;br /&gt;{&lt;br /&gt;    strncpy(message.text, text, MAX_MESSAGE_LENGTH);&lt;br /&gt;    &lt;br /&gt;    message.counter = 120;&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;setStatusMessage&lt;/span&gt; sets a new message and resets the counter to 120, which is approximately 2 seconds.    The remaining files and functions have been covered in the basic tutorials so we will not look at them.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;The editor is incredibly basic, but in future tutorials we will improve it to meet the needs of the game. In the next tutorial we will implement collision detection to allow an entity to move around the map.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial13.tar.gz/download"&gt;tutorial13.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-8429977378032962943?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/8429977378032962943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-3-tile-based.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/8429977378032962943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/8429977378032962943'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-3-tile-based.html' title='Intermediate Game Tutorial #3 - A Tile Based Map Editor'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-yfhSg08lNUU/ToDaRPGi7XI/AAAAAAAAAzQ/irRnm0VcAfk/s72-c/tutorial13.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-5300594239576680220</id><published>2011-10-02T06:21:00.000-07:00</published><updated>2011-10-02T06:21:22.190-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='map'/><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='tile'/><title type='text'>Intermediate Game Tutorial #2 - Scrolling a Tile Based Map</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Intermediate Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Intermediate Game Tutorial #2 - Scrolling a Tile Based Map&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-GMti3PS2lXs/ToDaQ5WawQI/AAAAAAAAAzM/fw138oz28PQ/s1600/tutorial12.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-GMti3PS2lXs/ToDaQ5WawQI/AAAAAAAAAzM/fw138oz28PQ/s1600/tutorial12.gif" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Scrolling a tile based map&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;This tutorial demonstrates how to scroll around a tile based map.&lt;br /&gt;Compile and run tutorial12. The program will read the map data file and display the map on the screen. Use the arrow keys (not the ones on the numeric pad) to scroll the map around. Closing the window or pressing Escape will exit the program.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;In the previous tutorial, the map size was restricted to 20 x 15 tiles. We have updated the &lt;span class="code"&gt;Map&lt;/span&gt; structure to allow scrolling and also allow dynamic map sizes. Below is the change we have made to &lt;span class="code"&gt;structs.h&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Map&lt;br /&gt;{&lt;br /&gt;    int startX, startY;&lt;br /&gt;    int maxX, maxY;&lt;br /&gt;    int tile[MAX_MAP_Y][MAX_MAP_X];&lt;br /&gt;} Map;&lt;/pre&gt;There are 4 new variables in the structure now. The &lt;span class="code"&gt;startX&lt;/span&gt; and &lt;span class="code"&gt;startY&lt;/span&gt; variables define the starting horizontal and vertical positions when drawing our map. The &lt;span class="code"&gt;mapX&lt;/span&gt; and &lt;span class="code"&gt;mapY&lt;/span&gt; variables are used to limit the amount of scrolling that the map can do. This stops unused areas of the map from being displayed on the screen.    The map loading code in &lt;span class="code"&gt;map.c&lt;/span&gt; has changed to make use of these new variables: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void loadMap(char *name)&lt;br /&gt;{&lt;br /&gt;    int x, y;&lt;br /&gt;    FILE *fp;&lt;br /&gt;&lt;br /&gt;    fp = fopen(name, "rb");&lt;br /&gt;&lt;br /&gt;    /* If we can't open the map then exit */&lt;br /&gt;&lt;br /&gt;    if (fp == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Failed to open map %s\n", name);&lt;br /&gt;&lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Read the data from the file into the map */&lt;br /&gt;&lt;br /&gt;    for (y=0;y&amp;lt;MAX_MAP_Y;y++)&lt;br /&gt;    {&lt;br /&gt;        for (x=0;x&amp;lt;MAX_MAP_X;x++)&lt;br /&gt;        {&lt;br /&gt;            fscanf(fp, "%d", &amp;amp;map.tile[y][x]);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Set the start coordinates */&lt;br /&gt;    &lt;br /&gt;    map.startX = map.startY = 0;&lt;br /&gt;    &lt;br /&gt;    /* Set the maximum scroll position of the map */&lt;br /&gt;    &lt;br /&gt;    map.maxX = MAX_MAP_X * TILE_SIZE;&lt;br /&gt;    map.maxY = MAX_MAP_Y * TILE_SIZE;&lt;br /&gt;&lt;br /&gt;    /* Close the file afterwards */&lt;br /&gt;&lt;br /&gt;    fclose(fp);&lt;br /&gt;}&lt;/pre&gt;We set the &lt;span class="code"&gt;startX&lt;/span&gt; and &lt;span class="code"&gt;startY&lt;/span&gt; values of the map to 0. This will start drawing the map from the top left corner. We also set the &lt;span class="code"&gt;maxX&lt;/span&gt; and &lt;span class="code"&gt;maxY&lt;/span&gt; values to the maximum allowed size of the map. Later tutorials will look at setting this value more dynamically. We have also added another function to this file: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doMap()&lt;br /&gt;{&lt;br /&gt;    if (input.left == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startX -= SCROLL_SPEED;&lt;br /&gt;        &lt;br /&gt;        if (map.startX &amp;lt; 0)&lt;br /&gt;        {&lt;br /&gt;            map.startX = 0;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (input.right == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startX += SCROLL_SPEED;&lt;br /&gt;        &lt;br /&gt;        if (map.startX + SCREEN_WIDTH &amp;gt;= map.maxX)&lt;br /&gt;        {&lt;br /&gt;            map.startX = map.maxX - SCREEN_WIDTH;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (input.up == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startY -= SCROLL_SPEED;&lt;br /&gt;        &lt;br /&gt;        if (map.startY &amp;lt; 0)&lt;br /&gt;        {&lt;br /&gt;            map.startY = 0;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (input.down == 1)&lt;br /&gt;    {&lt;br /&gt;        map.startY += SCROLL_SPEED;&lt;br /&gt;        &lt;br /&gt;        if (map.startY + SCREEN_HEIGHT &amp;gt;= map.maxY)&lt;br /&gt;        {&lt;br /&gt;            map.startY = map.maxY - SCREEN_HEIGHT;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;doMap&lt;/span&gt; processes the input passed to it, much in the same way that we processed player movement in previous tutorials. As always, we do not allow the &lt;span class="code"&gt;startX&lt;/span&gt; and &lt;span class="code"&gt;startY&lt;/span&gt; values to be less than 0. The maximum values are slightly more complicated though. We must not allow the screen to scroll past the &lt;span class="code"&gt;maxX&lt;/span&gt; value, but we must also take into account the screen's width when checking this. So, if the &lt;span class="code"&gt;startX&lt;/span&gt; plus the screen's width is greater than or equal to the &lt;span class="code"&gt;maxX&lt;/span&gt;, we set the &lt;span class="code"&gt;startX&lt;/span&gt; to &lt;span class="code"&gt;maxX&lt;/span&gt; and subtract the screen's width from it. We do the same for the vertical movement too. The final function is a revised version of the map drawing function: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void drawMap()&lt;br /&gt;{&lt;br /&gt;    int x, y, mapX, x1, x2, mapY, y1, y2;&lt;br /&gt;&lt;br /&gt;    mapX = map.startX / TILE_SIZE;&lt;br /&gt;    x1 = (map.startX % TILE_SIZE) * -1;&lt;br /&gt;    x2 = x1 + SCREEN_WIDTH + (x1 == 0 ? 0 : TILE_SIZE);&lt;br /&gt;    &lt;br /&gt;    mapY = map.startY / TILE_SIZE;&lt;br /&gt;    y1 = (map.startY % TILE_SIZE) * -1;&lt;br /&gt;    y2 = y1 + SCREEN_HEIGHT + (y1 == 0 ? 0 : TILE_SIZE);&lt;br /&gt;    &lt;br /&gt;    /* Draw the background */&lt;br /&gt;    &lt;br /&gt;    drawImage(backgroundImage, 0, 0);&lt;br /&gt;&lt;br /&gt;    /* Draw the map starting at the startX and startY */&lt;br /&gt;    &lt;br /&gt;    for (y=y1;y&amp;lt;y2;y+=TILE_SIZE)&lt;br /&gt;    {&lt;br /&gt;        mapX = map.startX / TILE_SIZE;&lt;br /&gt;        &lt;br /&gt;        for (x=x1;x&amp;lt;x2;x+=TILE_SIZE)&lt;br /&gt;        {&lt;br /&gt;            if (map.tile[mapY][mapX] != 0)&lt;br /&gt;            {&lt;br /&gt;                drawImage(brickImage, x, y);&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            mapX++;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        mapY++;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;When drawing a scrolled map, we must be mindful to draw tiles that are only partially on the screen. If we don't do this then tiles will pop in and out of existance when scrolling the map. We first get the starting horizontal index by dividing the &lt;span class="code"&gt;startX&lt;/span&gt; by the &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt;. This will give us the tile to start with, including any tiles that are to be partially drawn. Next, we set the starting x coordinate, &lt;span class="code"&gt;x1&lt;/span&gt;, to the remainder of the &lt;span class="code"&gt;startX&lt;/span&gt; divided by the &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt;. This will require slightly more explaination: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;mapX = map.startX / TILE_SIZE;&lt;/pre&gt;Suppose the &lt;span class="code"&gt;startX&lt;/span&gt; is 24. This will make the &lt;span class="code"&gt;mapX&lt;/span&gt; 0 (since it is an int and therefore we get no decimal part). This means that we start at index 0 for the horizontal drawing. However, we also need to know where on the screen to start drawing the tiles. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;x1 = (map.startX % TILE_SIZE) * -1;&lt;/pre&gt;The remainder will be 24, but we do not want to start drawing at 24 pixels. Since we have moved 24 pixels to the right, tile 0 must be 24 pixels off the left hand side of the screen, so we will set the value to negative to achieve this. Finally, we need to know where to stop drawing: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;x2 = x1 + SCREEN_WIDTH + (x1 == 0 ? 0 : TILE_SIZE);&lt;/pre&gt;We take the starting coordinate and add on the screen width. We also have to bear in mind though that we may have started drawing off screen. If we did then we need to draw an extra tile otherwise we will have a few blank pixels at the end of the screen. The easiest way to check this is to test if our starting value is 0 and, if it was not, then we add on an extra tile at the end. We apply the same logic to the vertical drawing. Finally we, draw the blocks to the screen: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;for (y=y1;y&amp;lt;y2;y+=TILE_SIZE)&lt;br /&gt;{&lt;br /&gt;    mapX = map.startX / TILE_SIZE;&lt;br /&gt;    &lt;br /&gt;    for (x=x1;x&amp;lt;x2;x+=TILE_SIZE)&lt;br /&gt;    {&lt;br /&gt;        if (map.tile[mapY][mapX] != 0)&lt;br /&gt;        {&lt;br /&gt;            drawImage(brickImage, x, y);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        mapX++;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    mapY++;&lt;br /&gt;}&lt;/pre&gt;The loop is simple enough, we start at &lt;span class="code"&gt;y1&lt;/span&gt; and loop through to &lt;span class="code"&gt;y2&lt;/span&gt;. &lt;span class="code"&gt;mapY&lt;/span&gt; and &lt;span class="code"&gt;mapX&lt;/span&gt; are our tile indexes. At the start of the outer loop, we reset &lt;span class="code"&gt;mapX&lt;/span&gt; because we will increment it in our inner loop. In our inner loop, we test the value of the tile at the current index and, if it is not 0, we draw the tile to the coordinates in our loop. Notice that we only want to draw what's going to be displayed on the screen. Drawing the entire map every single frame, particularly if the map is very big will waste a lot of CPU and slow down a game.    The remaining files and functions have been covered in the basic tutorials so we will not look at them.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Implementing scrolling does require a small amount of care to ensure that it is done correctly. The map is in the same format as before so you can again edit the file to change the map layout. In the next tutorial we will create a map editor to assist with the creation of maps.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial12.tar.gz/download"&gt;tutorial12.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-5300594239576680220?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/5300594239576680220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-2-scrolling.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/5300594239576680220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/5300594239576680220'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-2-scrolling.html' title='Intermediate Game Tutorial #2 - Scrolling a Tile Based Map'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-GMti3PS2lXs/ToDaQ5WawQI/AAAAAAAAAzM/fw138oz28PQ/s72-c/tutorial12.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-4778326150618869263</id><published>2011-10-02T06:19:00.000-07:00</published><updated>2011-10-02T06:20:18.965-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='map'/><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='tile'/><title type='text'>Intermediate Game Tutorial #1 - Displaying a Tile Based Map</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Intermediate Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Intermediate Game Tutorial #1 - Displaying a Tile Based Map&lt;/span&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-ujMVOIxFPhc/ToDaPB4Q4FI/AAAAAAAAAzI/zLwguES7cos/s1600/tutorial11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-ujMVOIxFPhc/ToDaPB4Q4FI/AAAAAAAAAzI/zLwguES7cos/s320/tutorial11.png" width="320" /&gt;&lt;/a&gt;&lt;span style="font-size: 14pt;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;A tile based map&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;We will now look at platform games and the use of tiles to display maps.&lt;br /&gt;Compile and run tutorial11. The program will read the map data file and display the map on the screen. Closing the window or pressing Escape will exit the program.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;When creating a tile based game, we break the screen up into a grid. In this tutorial we create a tile size of 32x32 pixels giving us 20 tiles horizontally and 15 tiles vertically. We will look at &lt;span class="code"&gt;structs.h&lt;/span&gt; to begin with: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Map&lt;br /&gt;{&lt;br /&gt;    int tile[MAX_MAP_Y][MAX_MAP_X];&lt;br /&gt;} Map;&lt;/pre&gt;We define our &lt;span class="code"&gt;Map&lt;/span&gt; structure which contains an multidimensional array of ints. The maximum size of this array is defined by &lt;span class="code"&gt;MAX_MAP_Y&lt;/span&gt; and &lt;span class="code"&gt;MAX_MAP_X&lt;/span&gt; which are defined in &lt;span class="code"&gt;defs.h&lt;/span&gt;.    We have made a minor change to &lt;span class="code"&gt;init.c&lt;/span&gt;. The following command &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_ShowCursor(SDL_DISABLE);&lt;/pre&gt;will hide the mouse cursor when it is moved inside the SDL window.    In main.c, we load up the brick image, a background image and read the map data as follows: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Load the brick image */&lt;br /&gt;&lt;br /&gt;brickImage = loadImage("gfx/brick.png");&lt;br /&gt;&lt;br /&gt;/* If we get back a NULL image, just exit */&lt;br /&gt;&lt;br /&gt;if (brickImage == NULL)&lt;br /&gt;{&lt;br /&gt;    exit(1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Load the background image */&lt;br /&gt;&lt;br /&gt;backgroundImage = loadImage("gfx/background.png");&lt;br /&gt;&lt;br /&gt;/* If we get back a NULL image, just exit */&lt;br /&gt;&lt;br /&gt;if (backgroundImage == NULL)&lt;br /&gt;{&lt;br /&gt;    exit(1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;loadMap("data/maps/map01.dat");&lt;/pre&gt;The &lt;span class="code"&gt;loadImage&lt;/span&gt; function is our standard image loading function. The &lt;span class="code"&gt;loadMap&lt;/span&gt; function takes the filename of the map file that we wish to load. We will look at this shortly. Once we have successfully loaded all of our resources we enter the standard main loop and wait for user input. We will now at the map loading functions.    &lt;span class="code"&gt;map.c&lt;/span&gt; contains two functions to deal with loading the map and rendering it to the screen. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void loadMap(char *name)&lt;br /&gt;{&lt;br /&gt;    int x, y;&lt;br /&gt;    FILE *fp;&lt;br /&gt;&lt;br /&gt;    fp = fopen(name, "rb");&lt;br /&gt;&lt;br /&gt;    /* If we can't open the map then exit */&lt;br /&gt;&lt;br /&gt;    if (fp == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Failed to open map %s\n", name);&lt;br /&gt;&lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Read the data from the file into the map */&lt;br /&gt;&lt;br /&gt;    for (y=0;y&amp;lt;MAX_MAP_Y;y++)&lt;br /&gt;    {&lt;br /&gt;        for (x=0;x&amp;lt;MAX_MAP_X;x++)&lt;br /&gt;        {&lt;br /&gt;            fscanf(fp, "%d", &amp;amp;map.tile[y][x]);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /* Close the file afterwards */&lt;br /&gt;&lt;br /&gt;    fclose(fp);&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;loadMap&lt;/span&gt; takes the filename of the map we wish to load. The data file is a very simple text file containing 0s and 1s to describe the map layout. We will take a brief look at this file: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0&lt;br /&gt;0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0&lt;br /&gt;1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1&lt;br /&gt;1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1&lt;/pre&gt;A 0 denotes a blank tile and 1 denotes a brick tile. Note that we must include either a space or carriage return between the digits so that scanf treats them as individual numbers and not one large number. Once we have successfully opened the file, we read in the map data one row at a time, one column at time. Once we are done we close the file. This gives us a multidimensional array containing our map data. The second function in the file deals with drawing the map: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void drawMap()&lt;br /&gt;{&lt;br /&gt;    int x, y;&lt;br /&gt;    &lt;br /&gt;    /* Draw the background */&lt;br /&gt;    &lt;br /&gt;    drawImage(backgroundImage, 0, 0);&lt;br /&gt;&lt;br /&gt;    /* Draw the map */&lt;br /&gt;&lt;br /&gt;    for (y=0;y&amp;lt;MAX_MAP_Y;y++)&lt;br /&gt;    {&lt;br /&gt;        for (x=0;x&amp;lt;MAX_MAP_X;x++)&lt;br /&gt;        {&lt;br /&gt;            if (map.tile[y][x] != 0)&lt;br /&gt;            {&lt;br /&gt;                drawImage(brickImage, x * TILE_SIZE, y * TILE_SIZE);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;First, we draw the background, just so the screen has some more colour to it. We then loop through the map from top to bottom, from left to right and if the tile at the array index is not 0, then we will draw a brick. Note that we multiply the &lt;span class="code"&gt;x&lt;/span&gt; and &lt;span class="code"&gt;y&lt;/span&gt; values up by &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt;. This is because we only have 20 tiles horizontally and 15 vertically as defined by &lt;span class="code"&gt;MAX_MAP_X&lt;/span&gt; and &lt;span class="code"&gt;MAX_MAP_Y&lt;/span&gt;, so we need to scale up the position of the tile according to &lt;span class="code"&gt;TILE_SIZE&lt;/span&gt;.    The remaining files and functions have been covered in the basic tutorials so we will not look at them.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Displaying a tile based map on the screen does not require a lot of code. Since the map data file is just a text file, it would be worth editing the file and changing some of the 0s and 1s to produce a different map. Ensure though that you have 20 digits on each row and 15 rows in the file to ensure that the file loads up correctly.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial11.tar.gz/download"&gt;tutorial11.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-4778326150618869263?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/4778326150618869263/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-1-displaying.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4778326150618869263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4778326150618869263'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/10/intermediate-game-tutorial-1-displaying.html' title='Intermediate Game Tutorial #1 - Displaying a Tile Based Map'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-ujMVOIxFPhc/ToDaPB4Q4FI/AAAAAAAAAzI/zLwguES7cos/s72-c/tutorial11.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-1040832264619258473</id><published>2011-09-30T10:34:00.000-07:00</published><updated>2011-10-02T06:19:18.531-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='controls'/><title type='text'>Basic Game Tutorial #18 - Redefining controls</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #18 - Redefining controls&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-UsS4afJIVHk/ToDaSLPD3QI/AAAAAAAAAzc/ak94iBNRPcM/s1600/tutorial18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="251" src="http://3.bp.blogspot.com/-UsS4afJIVHk/ToDaSLPD3QI/AAAAAAAAAzc/ak94iBNRPcM/s320/tutorial18.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;a href="http://reddwarf.local/images/tutorials/tutorial18.png"&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Redefining controls&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;This tutorial will demonstrate how to allow a user to redefine the controls for a game.&lt;br /&gt;Compile and run tutorial18. You will be prompted to enter the controls to move the ship. Once you have entered them all you can move the ship around and fire using the controls you defined. Pressing Escape will allow you to redefine the controls again, pressing escape whilst on this screen will exit the program.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;The basic idea behind redefining controls is that you specify what key or joystick button has to be pressed to perform the onscreen action. This is accomplished by creating another &lt;span class="code"&gt;Control&lt;/span&gt; structure to store your defined values. When you press a key or joystick button, this value is compared against the custom controls to see if one of them matches. If it does then the appropriate action will be performed.&lt;br /&gt;The program comprises of two parts, defining the controls and then moving the ship with the defined controls. In &lt;span class="code"&gt;defs.h&lt;/span&gt; we add a couple of defines to assist with the program flow  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;#define IN_REDEFINE 0&lt;br /&gt;#define IN_GAME 1&lt;/pre&gt;and add a varaible called &lt;span class="code"&gt;status&lt;/span&gt; to the &lt;span class="code"&gt;Game&lt;/span&gt; struct  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Game&lt;br /&gt;{&lt;br /&gt; int score, status;&lt;br /&gt; SDL_Surface *screen;&lt;br /&gt; TTF_Font *font;&lt;br /&gt; SDL_Joystick *joystick;&lt;br /&gt;} Game;&lt;/pre&gt;We will start with defining the controls.  In &lt;span class="code"&gt;structs.h&lt;/span&gt; we add another structure to assist with prompting the user to input their custom controls. It is very basic but serves its purpose for the tutorial.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Redefine&lt;br /&gt;{&lt;br /&gt; int redefineIndex;&lt;br /&gt; char redefineString[255];&lt;br /&gt;} Redefine;&lt;/pre&gt;&lt;span class="code"&gt;redefineIndex&lt;/span&gt; simply stores what key we're trying to redefine and &lt;span class="code"&gt;redefineString&lt;/span&gt; is for the onscreen text. A fully fledged game would present the user  with a menu and allow them to choose which control they want to redefine.&lt;br /&gt;In &lt;span class="code"&gt;main.c&lt;/span&gt; we initialize the redefineIndex 0 and blank the redefineString.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Reset the redefine index */&lt;br /&gt;&lt;br /&gt;redefine.redefineIndex = 0;&lt;br /&gt;redefine.redefineString[0] = '\0';&lt;/pre&gt;We then enter the main loop and examine the &lt;span class="code"&gt;Game&lt;/span&gt; status to determine whether we should be prompting the user to customize the controls or playing the game.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (game.status == IN_REDEFINE)&lt;br /&gt;{&lt;br /&gt; /* Handle the key redefining */&lt;br /&gt; &lt;br /&gt; doRedefine();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt; /* Get the input */&lt;br /&gt; &lt;br /&gt; getInput();&lt;br /&gt; &lt;br /&gt; /* Update the player's position */&lt;br /&gt; &lt;br /&gt; doPlayer();&lt;br /&gt; &lt;br /&gt; /* Update the entities */&lt;br /&gt; &lt;br /&gt; doEntities();&lt;br /&gt; &lt;br /&gt; /* Do the collisions */&lt;br /&gt; &lt;br /&gt; doCollisions();&lt;br /&gt; &lt;br /&gt; /* Draw everything */&lt;br /&gt; &lt;br /&gt; draw();&lt;br /&gt;}&lt;/pre&gt;We will look at the &lt;span class="code"&gt;doRedefine&lt;/span&gt; function first.  In &lt;span class="code"&gt;redefine.c&lt;/span&gt;, we check if the &lt;span class="code"&gt;redefineString&lt;/span&gt; is blank. If it is then we will use the &lt;span class="code"&gt;redefineIndex&lt;/span&gt; to determine which control we are currently prompting the user to define and generate the appropriate string. Next we call &lt;span class="code"&gt;flushInputs&lt;/span&gt;, this function is in &lt;span class="code"&gt;input.c&lt;/span&gt; and is defined as follows  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void flushInputs()&lt;br /&gt;{&lt;br /&gt; SDL_Event event;&lt;br /&gt;&lt;br /&gt; while (SDL_PollEvent(&amp;amp;event)) {}&lt;br /&gt;}&lt;/pre&gt;This code simply clears out any pending events so prevent a key press  being picked up before the user is ready. Next we wait until the user presses a key or joystick button  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;int getSingleInput()&lt;br /&gt;{&lt;br /&gt; int key;&lt;br /&gt; SDL_Event event;&lt;br /&gt;&lt;br /&gt; key = -2;&lt;br /&gt;&lt;br /&gt; if (SDL_PollEvent(&amp;amp;event))&lt;br /&gt; {&lt;br /&gt;  switch (event.type)&lt;br /&gt;  {&lt;br /&gt;   case SDL_QUIT:&lt;br /&gt;    exit(0);&lt;br /&gt;   break;&lt;br /&gt;&lt;br /&gt;   case SDL_KEYDOWN:&lt;br /&gt;    key = event.key.keysym.sym;&lt;br /&gt;   break;&lt;br /&gt;   &lt;br /&gt;   case SDL_JOYAXISMOTION:&lt;br /&gt;    if (abs(event.jaxis.value) &amp;gt; DEAD_ZONE)&lt;br /&gt;    {&lt;br /&gt;     key = -3;&lt;br /&gt;    }&lt;br /&gt;   break;&lt;br /&gt;&lt;br /&gt;   case SDL_JOYBUTTONDOWN:&lt;br /&gt;    key = event.jbutton.button;&lt;br /&gt;   break;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if (key == SDLK_ESCAPE)&lt;br /&gt; {&lt;br /&gt;  exit(0);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; return key;&lt;br /&gt;}&lt;/pre&gt;This function will return -2 if no key is pressed, so if this happens we  will continue to wait until a valid input is received. If the user presses Escape during this loop then the program will simply exit. Note  that while joystick buttons are captured and processed,  joystick movement events will be ignored, but the program will  acknowledge that a valid input has been entered. This is because  capturing joystick movement is not very simple since it is analog based.  Once a valid button key has been captured, we can assign the value to  our custom &lt;span class="code"&gt;Control&lt;/span&gt; structure. Again, we use the &lt;span class="code"&gt;redefineIndex&lt;/span&gt; to determine which control to assign the value to. Next, we increment the  &lt;span class="code"&gt;redefineIndex&lt;/span&gt; to move to the next control and blank the &lt;span class="code"&gt;redefineString&lt;/span&gt;.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;switch (redefine.redefineIndex)&lt;br /&gt;{&lt;br /&gt; case 0:&lt;br /&gt;  customControl.left = key;&lt;br /&gt;  break;&lt;br /&gt;  &lt;br /&gt; case 1:&lt;br /&gt;  customControl.right = key;&lt;br /&gt;  break;&lt;br /&gt;  &lt;br /&gt; case 2:&lt;br /&gt;  customControl.up = key;&lt;br /&gt;  break;&lt;br /&gt;  &lt;br /&gt; case 3:&lt;br /&gt;  customControl.down = key;&lt;br /&gt;  break;&lt;br /&gt;  &lt;br /&gt; default:&lt;br /&gt;  customControl.fire = key;&lt;br /&gt;  break;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;redefine.redefineIndex++;&lt;br /&gt;&lt;br /&gt;redefine.redefineString[0] = '\0';&lt;br /&gt;&lt;br /&gt;if (redefine.redefineIndex == 5)&lt;br /&gt;{&lt;br /&gt; redefine.redefineIndex = 0;&lt;br /&gt; &lt;br /&gt; game.status = IN_GAME;&lt;br /&gt;}&lt;/pre&gt;If the &lt;span class="code"&gt;redefineIndex&lt;/span&gt; is equal to 5 then we have input all the available controls and can then let the user try them out. We set the &lt;span class="code"&gt;status&lt;/span&gt; of the &lt;span class="code"&gt;Game&lt;/span&gt; structure to &lt;span class="code"&gt;IN_GAME&lt;/span&gt; and reset the &lt;span class="code"&gt;redefineIndex&lt;/span&gt; to 0. When the main loop checks the &lt;span class="code"&gt;status&lt;/span&gt; of &lt;span class="code"&gt;Game&lt;/span&gt; it will present the ship on the screen and allow the user to the move it around.   We will now look at how the custom controls are handled in &lt;span class="code"&gt;input.c&lt;/span&gt;. The follow code snippet demonstrates this  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;case SDL_KEYDOWN:&lt;br /&gt; key = event.key.keysym.sym;&lt;br /&gt; &lt;br /&gt; if (key == customControl.left)&lt;br /&gt; {&lt;br /&gt;  input.left = 1;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; else if (key == customControl.right)&lt;br /&gt; {&lt;br /&gt;  input.right = 1;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; /* Remainder omitted */&lt;br /&gt; break;&lt;br /&gt;&lt;br /&gt;case SDL_KEYUP:&lt;br /&gt; key = event.key.keysym.sym;&lt;br /&gt; &lt;br /&gt; if (key == customControl.left)&lt;br /&gt; {&lt;br /&gt;  input.left = 0;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; else if (key == customControl.right)&lt;br /&gt; {&lt;br /&gt;  input.right = 0;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /* Remainder omitted */&lt;br /&gt; break;&lt;br /&gt; &lt;br /&gt;case SDL_JOYBUTTONDOWN:&lt;br /&gt; key = event.jbutton.button;&lt;br /&gt; &lt;br /&gt; if (key == customControl.left)&lt;br /&gt; {&lt;br /&gt;  input.left = 1;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; else if (key == customControl.right)&lt;br /&gt; {&lt;br /&gt;  input.right = 1;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /* Remainder omitted */&lt;br /&gt; break;&lt;br /&gt; &lt;br /&gt;case SDL_JOYBUTTONUP:&lt;br /&gt; key = event.jbutton.button;&lt;br /&gt; &lt;br /&gt; if (key == customControl.left)&lt;br /&gt; {&lt;br /&gt;  input.left = 0;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;   else if (key == customControl.right)&lt;br /&gt; {&lt;br /&gt;  input.right = 0;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /* Remainder omitted */&lt;br /&gt; break;&lt;br /&gt; &lt;br /&gt;case SDL_JOYAXISMOTION:&lt;br /&gt; /* Horizontal movement */&lt;br /&gt; &lt;br /&gt; if (event.jaxis.axis == 0)&lt;br /&gt; {&lt;br /&gt;  if (event.jaxis.value &amp;lt; -DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.left = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else if (event.jaxis.value &amp;gt; DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.right = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;   input.left = 0;&lt;br /&gt;   input.right = 0;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /* Vertical movement */&lt;br /&gt; &lt;br /&gt; if (event.jaxis.axis == 1)&lt;br /&gt; {&lt;br /&gt;  if (event.jaxis.value &amp;lt; -DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.up = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else if (event.jaxis.value &amp;gt; DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.down = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;   input.up = 0;&lt;br /&gt;   input.down = 0;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; break;&lt;/pre&gt;As always, when an event is detected, we determine its type and get the value. In the case of the keyboard, we get the value of the key and check to see if it matches any of our custom controls. If it does then we set the relevant control on the &lt;span class="code"&gt;input&lt;/span&gt; structure. The same is true for joystick buttons. As you will see, joystick movement handling is handled as in the previous tutorial.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;Probably the hardest thing about allowing a user to customize controls is building an elegant interface to allow them to do so. How major games companies are able to spend tens of millions of dollars on games and then overlook something so simple is a mystery.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial18.tar.gz/download"&gt;tutorial18.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-1040832264619258473?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/1040832264619258473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-18-redefining.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/1040832264619258473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/1040832264619258473'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-18-redefining.html' title='Basic Game Tutorial #18 - Redefining controls'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-UsS4afJIVHk/ToDaSLPD3QI/AAAAAAAAAzc/ak94iBNRPcM/s72-c/tutorial18.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-3909127735946184094</id><published>2011-09-30T10:26:00.000-07:00</published><updated>2011-10-02T06:07:42.097-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='joystick'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Basic Game Tutorial #17 - Joystick movement</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #17 - Joystick movement&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 24pt; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-BWdkJSqyCmI/ToDaMJW6GqI/AAAAAAAAAys/sOqzSJ_Js-U/s1600/tutorial04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="253" src="http://1.bp.blogspot.com/-BWdkJSqyCmI/ToDaMJW6GqI/AAAAAAAAAys/sOqzSJ_Js-U/s320/tutorial04.png" width="320" /&gt;&lt;/a&gt;&lt;span style="font-size: 14pt;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Joystick movement&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;This tutorial will demonstrate how to use the joystick to move an image around the screen.&lt;br /&gt;Compile and run tutorial17. You can control the ship by using the joystick's joypad or analog stick. Pressing the fire button will fire a bullet.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;The structure for the joystick is an SDL_Joystick and holds all the information related to the joystick. It is stored  in the &lt;span class="code"&gt;Game&lt;/span&gt; struct:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Game&lt;br /&gt;{&lt;br /&gt; SDL_Joystick *joystick;&lt;br /&gt; SDL_Surface *screen;&lt;br /&gt;} Game;&lt;/pre&gt;In &lt;span class="code"&gt;defs.h&lt;/span&gt; we add the following definition:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;#define DEAD_ZONE 3200&lt;/pre&gt;This controls the joystick's analog control sensitivity, this will be discussed later.   Before using a joystick in SDL it must be opened. This is performed in the &lt;span class="code"&gt;SDL_Init&lt;/span&gt; function in &lt;span class="code"&gt;init.c&lt;/span&gt; &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK) &amp;lt; 0)&lt;/pre&gt;The number of joysticks detected by SDL can be queried by the function &lt;span class="code"&gt;SDL_NumJoysticks&lt;/span&gt; &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;joystickCount = SDL_NumJoysticks();&lt;/pre&gt;Since this tutorial deals with using the joystick for movement, we will exit the program if no joysticks were detected. A game that allows joystick or keyboard input would want to handle this event differently.  Now that we have detected a joystick, we need to open it and store the reference to the joystick. This is done with the following.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;game.joystick = SDL_JoystickOpen(0);&lt;/pre&gt;This will open the first joystick detected by SDL. If you have multiple joysticks attached to the system then we can open them instead by specifying the index number. As always, the index number starts at 0 and must be less than  &lt;span class="code"&gt;SDL_NumJoysticks&lt;/span&gt;. Specifying a negative number or a number greater than &lt;span class="code"&gt;SDL_NumJoysticks&lt;/span&gt; will cause a segfault. A joystick opened by SDL must be closed when the program exits to free the resources. The following lines  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;buttonCount = SDL_JoystickNumButtons(game.joystick);&lt;br /&gt;&lt;br /&gt;printf("Joystick has %d buttons\n", buttonCount);&lt;br /&gt;&lt;br /&gt;printf("Joystick has %d axes\n", SDL_JoystickNumAxes(game.joystick));&lt;/pre&gt;Are simply for information. In your game you might wish to raise an error if, say, the number of detected buttons is less than the number that your game requires. The only other addition to &lt;span class="code"&gt;init.c&lt;/span&gt; is the closing of the joystick in the &lt;span class="code"&gt;cleanup&lt;/span&gt; function.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Close the joystick */&lt;br /&gt;&lt;br /&gt;if (game.joystick != NULL)&lt;br /&gt;{&lt;br /&gt; SDL_JoystickClose(game.joystick);&lt;br /&gt;}&lt;/pre&gt;This will close the joystick and free the resources allocated to it.  In &lt;span class="code"&gt;input.c&lt;/span&gt; we add in some extra code to detect the events produced from the joystick  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;case SDL_JOYBUTTONDOWN:&lt;br /&gt; switch (event.jbutton.button)&lt;br /&gt; {&lt;br /&gt;  case 0:&lt;br /&gt;   input.fire = 1;&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt; break;&lt;br /&gt;&lt;br /&gt;case SDL_JOYBUTTONUP:&lt;br /&gt; switch (event.jbutton.button)&lt;br /&gt; {&lt;br /&gt;  case 0:&lt;br /&gt;   input.fire = 0;&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt; break;&lt;/pre&gt;These two case statements deal with the first joystick button being pressed and released. This raises an important point: There is no way to know what button is the first one. On a PS2 joypad it is the Triangle button, but on other joysticks it might be different, so you will have to try all the buttons until the ship fires a shot. Don't worry though, the button doesn't change every time you start the program! The next code snippet deals with moving the ship.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;case SDL_JOYAXISMOTION:&lt;br /&gt; /* Horizontal movement */&lt;br /&gt; &lt;br /&gt; if (event.jaxis.axis == 0)&lt;br /&gt; {&lt;br /&gt;  if (event.jaxis.value &amp;lt; -DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.left = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else if (event.jaxis.value &amp;gt; DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.right = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;   input.left = 0;&lt;br /&gt;   input.right = 0;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; /* Vertical movement */&lt;br /&gt; &lt;br /&gt; if (event.jaxis.axis == 1)&lt;br /&gt; {&lt;br /&gt;  if (event.jaxis.value &amp;lt; -DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.up = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else if (event.jaxis.value &amp;gt; DEAD_ZONE)&lt;br /&gt;  {&lt;br /&gt;   input.down = 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;   input.up = 0;&lt;br /&gt;   input.down = 0;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; break;&lt;/pre&gt;&lt;span class="code"&gt;SDL_JOYAXISMOTION&lt;/span&gt; is the event produced when the directional buttons on the joystick are pressed. When this happens, we need to check which axis was moved, either the horizontal or vertical. We do this by checking the &lt;span class="code"&gt;event.jaxis.axis&lt;/span&gt; value. 0 signifies a horizontal movement and 1 signifies a vertical movement. The next part is important when reading input from analog joysticks: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (event.jaxis.value &amp;lt; -DEAD_ZONE)&lt;br /&gt;{&lt;br /&gt; input.left = 1;&lt;br /&gt;}&lt;/pre&gt;The value generated from &lt;span class="code"&gt;event.jaxis.value&lt;/span&gt; is  between -32767 and 32767, with 0 as no movement. Some analog joysticks can be slightly sensitive or simply damaged and  will always generate a small movement event, which the input code would pick up. The best solution is to ignore these small values to  stop the ship from moving when the player doesn't want it to. The variable &lt;span class="code"&gt;DEAD_ZONE&lt;/span&gt;, tells the code to not process movement that is below its value. This is currently set to 3200 and is stored in &lt;span class="code"&gt;defs.h&lt;/span&gt;. This value is fairly reasonable but if you are still experiencing movement when the joystick is idle you should increase this value and recompile. A fully fledged game would allow this value to be configurable by the player.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Adding joystick support is quite simple, but as you can see, the joystick buttons may not be mapped in a desirable fashion. In the next tutorial, we will look at adding support for configuring controls.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial17.tar.gz/download"&gt;tutorial17.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-3909127735946184094?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/3909127735946184094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-17-joystick.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/3909127735946184094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/3909127735946184094'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-17-joystick.html' title='Basic Game Tutorial #17 - Joystick movement'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-BWdkJSqyCmI/ToDaMJW6GqI/AAAAAAAAAys/sOqzSJ_Js-U/s72-c/tutorial04.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-4852938004207483069</id><published>2011-09-27T12:05:00.000-07:00</published><updated>2011-09-27T12:05:17.934-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='basic'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Basic Game Tutorial #10 - A Basic Game</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #10 - A Basic Game&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-kaMxY3yqzLc/ToDaO1WOUiI/AAAAAAAAAzE/frzAIfWbQ0I/s1600/tutorial10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-kaMxY3yqzLc/ToDaO1WOUiI/AAAAAAAAAzE/frzAIfWbQ0I/s320/tutorial10.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;A simple game&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;This tutorial combines everything that we have learnt so far to create a basic rock dodging game. In this tutorial we will make use of reading input, collision detection, animation, playing sounds and SDL_TTF to create the game.&lt;br /&gt;Compile and run tutorial10. Use the arrow keys (not the ones on the numeric pad) to move the ship around the screen. Your score will increase for as long as you don't hit a rock. If you hit a rock then the ship will vanish and your score will stop increasing. The higher your score is, the more rocks that will appear on the screen.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;This is the most complex tutorial so far, but many of the methods used in this tutorial have been covered in previous tutorials so you should be quite familiar with them. We will start, as always, with &lt;span class="code"&gt;structs.h&lt;/span&gt;: &lt;br /&gt;The animation structure has changed slightly. This is because we cannot store the current frame index or the frame counter in the structure without making all of the rocks spin in synchronization. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Animation&lt;br /&gt;{&lt;br /&gt;    int frameCount;&lt;br /&gt;    SDL_Surface **frame;&lt;br /&gt;} Animation;&lt;/pre&gt;The current frame index and the counter have been moved to the &lt;span class="code"&gt;Entity&lt;/span&gt; structure: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Entity&lt;br /&gt;{&lt;br /&gt;    int active, speed;&lt;br /&gt;    int x, y, w, h;&lt;br /&gt;    int currentFrame, animID, frameTimer;&lt;br /&gt;    SDL_Surface *sprite;&lt;br /&gt;    void (*action)(void);&lt;br /&gt;    void (*draw)(void);&lt;br /&gt;} Entity;&lt;/pre&gt;We will use the &lt;span class="code"&gt;Entity&lt;/span&gt; structure for both the player and the rocks. The &lt;span class="code"&gt;currentFrame&lt;/span&gt; is used to store the index of the current image of the animation for this &lt;span class="code"&gt;Entity&lt;/span&gt;. &lt;span class="code"&gt;animID&lt;/span&gt; is the index of the animation that this &lt;span class="code"&gt;Entity&lt;/span&gt; is using and &lt;span class="code"&gt;frameTimer&lt;/span&gt; is the delay between moving onto the next frame in the animation. The rest of the variables should be familiar as they are used in previous tutorials. The other structures should also be familiar so we will move onto &lt;span class="code"&gt;animation.c&lt;/span&gt;.    The &lt;span class="code"&gt;loadAnimation&lt;/span&gt; function has changed. We now pass in the index of the ID of the animation we wish to load up and the data file of the animation. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void loadAnimation(int id, char *name)&lt;br /&gt;{&lt;br /&gt;    /* Load up the data file that describes the animation */&lt;br /&gt;    &lt;br /&gt;    int i;&lt;br /&gt;    FILE *fp = fopen(name, "rb");&lt;br /&gt;    char frameName[20];&lt;br /&gt;    &lt;br /&gt;    if (fp == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Failed to load animation file %s\n", name);&lt;br /&gt;        &lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Read the frame count */&lt;br /&gt;    &lt;br /&gt;    fscanf(fp, "%d", &amp;amp;animation[id].frameCount);&lt;br /&gt;    &lt;br /&gt;    /* Allocate space for the animation */&lt;br /&gt;    &lt;br /&gt;    animation[id].frame = (SDL_Surface **)malloc(animation[id].frameCount&lt;br /&gt;    * sizeof(SDL_Surface *));&lt;br /&gt;    &lt;br /&gt;    if (animation[id].frame == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Ran out of memory when creating the animation for %s\n", name);&lt;br /&gt;        &lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Now load up each frame */&lt;br /&gt;    &lt;br /&gt;    for (i=0;i&amp;lt;animation[id].frameCount;i++)&lt;br /&gt;    {&lt;br /&gt;        fscanf(fp, "%s", frameName);&lt;br /&gt;        &lt;br /&gt;        animation[id].frame[i] = loadImage(frameName);&lt;br /&gt;        &lt;br /&gt;        if (animation[id].frame[i] == NULL)&lt;br /&gt;        {&lt;br /&gt;            printf("Failed to load animation frame %s\n", frameName);&lt;br /&gt;            &lt;br /&gt;            exit(1);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;So instead of using a pointer to the animation, we are using an array of Animations. This will make adding extra animations easy in the future. We have added an extra function to &lt;span class="code"&gt;animation.c&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void loadAllAnimations()&lt;br /&gt;{&lt;br /&gt;    loadAnimation(ROCK_ANIMATION, "data/anim/rock.dat");&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;loadAllAnimations&lt;/span&gt; simply loads up the rock animation. If there were more animations then this function would load those too. There is also another new function, &lt;span class="code"&gt;freeAnimations&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void freeAnimations()&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;    &lt;br /&gt;    for (i=0;i&amp;lt;MAX_ANIMATIONS;i++)&lt;br /&gt;    {&lt;br /&gt;        freeAnimation(&amp;amp;animation[i]);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;This function loops though all the animations and frees them. This function will be called by &lt;span class="code"&gt;cleanup&lt;/span&gt; in &lt;span class="code"&gt;init.c&lt;/span&gt;.    We will skip over &lt;span class="code"&gt;audio.c&lt;/span&gt; since it has not changed. &lt;br /&gt;In &lt;span class="code"&gt;collisions.c&lt;/span&gt;, we have changed the implementation of the function &lt;span class="code"&gt;doCollisions&lt;/span&gt; &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doCollisions()&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;&lt;br /&gt;    /* Check each entity against the player, skipping over inactive ones */&lt;br /&gt;    &lt;br /&gt;    if (player.active == 0)&lt;br /&gt;    {&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    for (i=0;i&amp;lt;MAX_ENTITIES;i++)&lt;br /&gt;    {&lt;br /&gt;        if (entity[i].active == 0)&lt;br /&gt;        {&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        if (collision(entity[i].x, entity[i].y, entity[i].w, entity[i].h,&lt;br /&gt;        player.x, player.y, player.w, player.h) == 1)&lt;br /&gt;        {&lt;br /&gt;            /* If a collision occured, kill the player */&lt;br /&gt;            &lt;br /&gt;            player.active = 0;&lt;br /&gt;            &lt;br /&gt;            playSound(EXPLOSION_SOUND);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Since we are only checking against the player, we will return from the function immediately if the player is not active. If the player is active however, we loop through the Entities, skipping over any inactive ones and check for a player - Entity collision. If one has occured then we set the player to inactive and call &lt;span class="code"&gt;playSound&lt;/span&gt; to play an explosion.    We will skip over &lt;span class="code"&gt;draw.c&lt;/span&gt; since it does not contain any functions or calls that have not been seen in previous tutorials. &lt;br /&gt;&lt;span class="code"&gt;entity.c&lt;/span&gt; contains a new function for dealing with animation: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void drawAnimatedEntity()&lt;br /&gt;{&lt;br /&gt;    drawImage(animation[self-&amp;gt;animID].frame[self-&amp;gt;currentFrame], self-&amp;gt;x, self-&amp;gt;y);&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;drawAnimatedEntity&lt;/span&gt; makes use of the &lt;span class="code"&gt;self&lt;/span&gt; Entity pointer. We use the &lt;span class="code"&gt;animID&lt;/span&gt; and &lt;span class="code"&gt;currentFrame&lt;/span&gt; variables of the &lt;span class="code"&gt;Entity&lt;/span&gt;.    &lt;span class="code"&gt;font.c&lt;/span&gt;, &lt;span class="code"&gt;graphics.c&lt;/span&gt; and &lt;span class="code"&gt;input.c&lt;/span&gt; do not have any function calls not seen in previous tutorials so we will not cover them. &lt;br /&gt;As noted earlier, the &lt;span class="code"&gt;cleanup&lt;/span&gt; function in &lt;span class="code"&gt;init.c&lt;/span&gt; calls the &lt;span class="code"&gt;freeAnimations&lt;/span&gt; function. Apart from that it is the same. &lt;br /&gt;In &lt;span class="code"&gt;main.c&lt;/span&gt;, we load up our required resources, reset the starfield and then enter the main loop: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Get the input */&lt;br /&gt;&lt;br /&gt;getInput();&lt;br /&gt;&lt;br /&gt;/* Update the player's position */&lt;br /&gt;&lt;br /&gt;doPlayer();&lt;br /&gt;&lt;br /&gt;/* Add a rock */&lt;br /&gt;&lt;br /&gt;addRock(game.score);&lt;br /&gt;&lt;br /&gt;/* Update the entities */&lt;br /&gt;&lt;br /&gt;doEntities();&lt;br /&gt;&lt;br /&gt;/* Update the stars */&lt;br /&gt;&lt;br /&gt;doStars();&lt;br /&gt;&lt;br /&gt;/* Do the collisions */&lt;br /&gt;&lt;br /&gt;doCollisions();&lt;br /&gt;&lt;br /&gt;/* Draw everything */&lt;br /&gt;&lt;br /&gt;draw();&lt;br /&gt;&lt;br /&gt;/* Increment the player's score while the player's still alive */&lt;br /&gt;&lt;br /&gt;if (player.active == 1)&lt;br /&gt;{&lt;br /&gt;    game.score += 10;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Sleep briefly to stop sucking up all the CPU time */&lt;br /&gt;&lt;br /&gt;delay(frameLimit);&lt;br /&gt;&lt;br /&gt;frameLimit = SDL_GetTicks() + 16;&lt;/pre&gt;The function &lt;span class="code"&gt;addRock&lt;/span&gt; will attempt to add a new rock to the playfield. We will look at this function later. We also increment the player's score by 10 each frame. We will use the score to determine the odds of adding another rock to the playfield.    We have made a small change to the &lt;span class="code"&gt;drawPlayer&lt;/span&gt; function in &lt;span class="code"&gt;player.c&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void drawPlayer()&lt;br /&gt;{&lt;br /&gt;    /* Draw the image in the player structure */&lt;br /&gt;    &lt;br /&gt;    if (player.active == 1)&lt;br /&gt;    {&lt;br /&gt;        drawImage(player.sprite, player.x, player.y);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;This means that if the player is not active, i.e. it has been destroyed, then it will not be drawn on the screen. Finally, we will look at &lt;span class="code"&gt;rock.c&lt;/span&gt;    &lt;span class="code"&gt;rock.c&lt;/span&gt; has two functions: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void addRock(int score)&lt;br /&gt;{&lt;br /&gt;    int i, rockChance;&lt;br /&gt;    &lt;br /&gt;    /* The chance of a rock being added depends upon the player's score */&lt;br /&gt;    &lt;br /&gt;    if (score &amp;lt; 10000)&lt;br /&gt;    {&lt;br /&gt;        rockChance = rand() % 60;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (score &amp;lt; 20000)&lt;br /&gt;    {&lt;br /&gt;        rockChance = rand() % 45;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else if (score &amp;lt; 30000)&lt;br /&gt;    {&lt;br /&gt;        rockChance = rand() % 30;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        rockChance = rand() % 15;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (rockChance != 0)&lt;br /&gt;    {&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    i = getFreeEntity();&lt;br /&gt;    &lt;br /&gt;    if (i == -1)&lt;br /&gt;    {&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    entity[i].x = SCREEN_WIDTH + rand() % 100;&lt;br /&gt;    entity[i].y = rand() % SCREEN_HEIGHT;&lt;br /&gt;    entity[i].action = &amp;amp;moveRock;&lt;br /&gt;    entity[i].speed = 1 + (rand() % 5);&lt;br /&gt;    entity[i].draw = &amp;amp;drawAnimatedEntity;&lt;br /&gt;    entity[i].animID = ROCK_ANIMATION;&lt;br /&gt;    entity[i].currentFrame = 0;&lt;br /&gt;    entity[i].frameTimer = 3;&lt;br /&gt;    entity[i].w = animation[entity[i].animID].frame[entity[i].currentFrame]-&amp;gt;w;&lt;br /&gt;    entity[i].h = animation[entity[i].animID].frame[entity[i].currentFrame]-&amp;gt;h;&lt;br /&gt;}&lt;/pre&gt;We pass in the player's score to &lt;span class="code"&gt;addRock&lt;/span&gt;. The intention to make the game more difficult by increasing the probability of a rock appearing based upon the player's score. So when the player's score is less than 10,000 points, the chance of a rock appearing is 1 in 60, which means that a new rock will appear once a second. At 20,000 points the odds increase to 1 in 45, then 1 in 30 at 30,0000 and finally 1 in 15. The &lt;span class="code"&gt;rand&lt;/span&gt; function returns a random positive number which we use the modulus operator on the value to give us a number between 0 and n - 1, where n is the modulus value. If this value is not 0 then we will not create a rock and simply exit the function. &lt;br /&gt;Provided we need to create a rock, we call &lt;span class="code"&gt;getFreeEntity&lt;/span&gt; as we have in previous tutorials. We then set the &lt;span class="code"&gt;x&lt;/span&gt; and &lt;span class="code"&gt;y&lt;/span&gt; coordinates to random values and also set the &lt;span class="code"&gt;speed&lt;/span&gt; to a random value between 1 and 5. We set the &lt;span class="code"&gt;animID&lt;/span&gt; to &lt;span class="code"&gt;ROCK_ANIMATION&lt;/span&gt; which is the rock animation index. Since we have moved the animation frame index and frame counter to the &lt;span class="code"&gt;Entity&lt;/span&gt; structure, we set them here, using &lt;span class="code"&gt;currentFrame&lt;/span&gt; and &lt;span class="code"&gt;frameTimer&lt;/span&gt; respectively. We also set the width and height of the entity to the animation's current frame's width and height. The Entity's &lt;span class="code"&gt;action&lt;/span&gt; and &lt;span class="code"&gt;draw&lt;/span&gt; functions are set to &lt;span class="code"&gt;moveRock&lt;/span&gt; and &lt;span class="code"&gt;drawAnimatedEntity&lt;/span&gt;.    The &lt;span class="code"&gt;moveRock&lt;/span&gt; function moves the rock from right to left and also updates its animation: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;static void moveRock(void)&lt;br /&gt;{&lt;br /&gt;    /* Move the rock from right to left, once it goes off the screen, kill it */&lt;br /&gt;    &lt;br /&gt;    self-&amp;gt;x -= self-&amp;gt;speed;&lt;br /&gt;    &lt;br /&gt;    if (self-&amp;gt;x &amp;lt;= -self-&amp;gt;w)&lt;br /&gt;    {&lt;br /&gt;        self-&amp;gt;active = 0;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Update the animation frame */&lt;br /&gt;    &lt;br /&gt;    self-&amp;gt;frameTimer--;&lt;br /&gt;    &lt;br /&gt;    if (self-&amp;gt;frameTimer &amp;lt;= 0)&lt;br /&gt;    {&lt;br /&gt;        self-&amp;gt;frameTimer = 3;&lt;br /&gt;        self-&amp;gt;currentFrame++;&lt;br /&gt;        &lt;br /&gt;        if (self-&amp;gt;currentFrame &amp;gt;= animation[self-&amp;gt;animID].frameCount)&lt;br /&gt;        {&lt;br /&gt;            self-&amp;gt;currentFrame = 0;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The rock will move horizontally from right to left based upon its &lt;span class="code"&gt;speed&lt;/span&gt;. When its &lt;span class="code"&gt;x&lt;/span&gt; value is less than or equal to its negative width (i.e. it has completely moved off the left hand side of the screen), then it is made inactive. Otherwise we decrement its &lt;span class="code"&gt;frameTimer&lt;/span&gt; and if that value becomes less than or equal to 0 then we move to the next animation frame and reset the &lt;span class="code"&gt;frameTimer&lt;/span&gt;. If the &lt;span class="code"&gt;currentFrame&lt;/span&gt; is greater than or equal to the animation's &lt;span class="code"&gt;frameCount&lt;/span&gt; we reset the &lt;span class="code"&gt;currentFrame&lt;/span&gt; to 0.    The &lt;span class="code"&gt;stars.c&lt;/span&gt; file is the same as in the previous tutorial so we will pass over it too.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Hopefully if you have read all the tutorials then you will see that putting together a very simple game does not take too much effort and that a lot of the functions from earlier tutorials are just reused or extended as needed. If you are comfortable with this tutorial then you could try extending it to allow the player to fire bullets and destroy the rocks. In the next tutorial we will move onto more intermediate topics and create a basic platform game.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial10.tar.gz/download"&gt;tutorial10.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-4852938004207483069?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/4852938004207483069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-10-basic-game.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4852938004207483069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4852938004207483069'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-10-basic-game.html' title='Basic Game Tutorial #10 - A Basic Game'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-kaMxY3yqzLc/ToDaO1WOUiI/AAAAAAAAAzE/frzAIfWbQ0I/s72-c/tutorial10.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-2066608928393043637</id><published>2011-09-27T12:04:00.006-07:00</published><updated>2011-10-02T06:19:07.015-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='starfield'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Basic Game Tutorial #9 - Starfields</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #9 - Starfields&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-R0HPVxeARjA/ToDaN0lwKAI/AAAAAAAAAzA/e92Zzc0KURY/s1600/tutorial09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://4.bp.blogspot.com/-R0HPVxeARjA/ToDaN0lwKAI/AAAAAAAAAzA/e92Zzc0KURY/s320/tutorial09.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;A simple starfield&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=2066608928393043637" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;This tutorial demonstrates how to display a moving starfield on the screen.&lt;br /&gt;Compile and run tutorial09. The stars on the screen will move from right to left at various speeds. Pressing Escape or closing the window will exit the program.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;Creating a moving starfield is very simple and there are only a few files of note for this tutorial. First, we define a structure for our starfield in &lt;span class="code"&gt;structs.h&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Star&lt;br /&gt;{&lt;br /&gt;    int x, y, speed;&lt;br /&gt;} Star;&lt;/pre&gt;The &lt;span class="code"&gt;x&lt;/span&gt; and &lt;span class="code"&gt;y&lt;/span&gt; variables define the star's location on the screen and the &lt;span class="code"&gt;speed&lt;/span&gt; defines its movement speed. Next we will look at the &lt;span class="code"&gt;stars.c&lt;/span&gt; file.    &lt;span class="code"&gt;stars.c&lt;/span&gt; contains 4 functions: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void resetStars()&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;&lt;br /&gt;    for (i=0;i&amp;lt;MAX_STARS;i++)&lt;br /&gt;    {&lt;br /&gt;        star[i].x = rand() % SCREEN_WIDTH;&lt;br /&gt;        star[i].y = rand() % SCREEN_HEIGHT;&lt;br /&gt;        star[i].speed = 1 + (rand() % 12);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;resetStars&lt;/span&gt; randomly places all of the stars on the screen with a random speed. We need to do this before entering our main loop otherwise all of the stars might suddenly all appear on the right hand side of the screen which wouldlook wrong. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doStars()&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;&lt;br /&gt;    for (i=0;i&amp;lt;MAX_STARS;i++)&lt;br /&gt;    {&lt;br /&gt;        star[i].x -= star[i].speed;&lt;br /&gt;&lt;br /&gt;        if (star[i].x &amp;lt; 0)&lt;br /&gt;        {&lt;br /&gt;            star[i].x = SCREEN_WIDTH + rand() % 20;&lt;br /&gt;            star[i].y = rand() % SCREEN_HEIGHT;&lt;br /&gt;            star[i].speed = 1 + (rand() % 12);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;doStars&lt;/span&gt; loops though all of the stars and moves them across the screen from right to left by subtracting their &lt;span class="code"&gt;speed&lt;/span&gt; from their current &lt;span class="code"&gt;x&lt;/span&gt; position. If a star's &lt;span class="code"&gt;x&lt;/span&gt; position becomes negative then it has moved off the screen, so we randomly set its &lt;span class="code"&gt;x&lt;/span&gt; position to be the screen's width plus a random amount to stop it appearing immediately and also set its &lt;span class="code"&gt;y&lt;/span&gt; and &lt;span class="code"&gt;speed&lt;/span&gt;. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void drawStars()&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;    SDL_Rect rect;&lt;br /&gt;&lt;br /&gt;    for (i=0;i&amp;lt;MAX_STARS;i++)&lt;br /&gt;    {&lt;br /&gt;        if (star[i].x &amp;lt; SCREEN_WIDTH)&lt;br /&gt;        {&lt;br /&gt;            rect.x = star[i].x;&lt;br /&gt;            rect.y = star[i].y;&lt;br /&gt;            rect.w = 1;&lt;br /&gt;            rect.h = 1;&lt;br /&gt;    &lt;br /&gt;            SDL_FillRect(screen, &amp;amp;rect, getStarColor(star[i].speed));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;drawStars&lt;/span&gt; is another simple function. We loop through all the stars and, if their &lt;span class="code"&gt;x&lt;/span&gt; position is on the screen, we draw it using &lt;span class="code"&gt;SDL_FillRect&lt;/span&gt;. We determine its colour by calling the function &lt;span class="code"&gt;getStarColor&lt;/span&gt; which is described below. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;int getStarColor(int speed)&lt;br /&gt;{&lt;br /&gt;    SDL_Color color;&lt;br /&gt;    &lt;br /&gt;    switch (speed)&lt;br /&gt;    {&lt;br /&gt;        case 1:&lt;br /&gt;        case 2:&lt;br /&gt;        case 3:&lt;br /&gt;            color.r = 159;&lt;br /&gt;            color.g = 159;&lt;br /&gt;            color.b = 159;&lt;br /&gt;            break;&lt;br /&gt;                &lt;br /&gt;        case 4:&lt;br /&gt;        case 5:&lt;br /&gt;        case 6:&lt;br /&gt;            color.r = 191;&lt;br /&gt;            color.g = 191;&lt;br /&gt;            color.b = 191;&lt;br /&gt;            break;&lt;br /&gt;                &lt;br /&gt;        case 7:&lt;br /&gt;        case 8:&lt;br /&gt;        case 9:&lt;br /&gt;            color.r = 223;&lt;br /&gt;            color.g = 223;&lt;br /&gt;            color.b = 223;&lt;br /&gt;            break;&lt;br /&gt;            &lt;br /&gt;        default:&lt;br /&gt;            color.r = 255;&lt;br /&gt;            color.g = 255;&lt;br /&gt;            color.b = 255;&lt;br /&gt;            break;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return SDL_MapRGB(screen-&amp;gt;format, color.r, color.g, color.b);&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;getStarColor&lt;/span&gt; takes a simple parameter, the speed we wish to test. We then switch this speed and set the RGB values of the &lt;span class="code"&gt;SDL_Color&lt;/span&gt;. The lower the speed, the darker the star will be, since it's further away. Finally, we use &lt;span class="code"&gt;SDL_MapRGB&lt;/span&gt; to get the correct value for the colour we've chosen and return it.   In &lt;span class="code"&gt;main.c&lt;/span&gt; we animate the stars as follows: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Initialise the stars */&lt;br /&gt;&lt;br /&gt;resetStars();&lt;br /&gt;&lt;br /&gt;/* Loop indefinitely for messages */&lt;br /&gt;&lt;br /&gt;while (go == 1)&lt;br /&gt;{&lt;br /&gt;    getInput();&lt;br /&gt;    &lt;br /&gt;    /* Update the stars */&lt;br /&gt;    &lt;br /&gt;    doStars();&lt;br /&gt;    &lt;br /&gt;    /* Blank the screen */&lt;br /&gt;    &lt;br /&gt;    SDL_FillRect(screen, NULL, 0);&lt;br /&gt;    &lt;br /&gt;    /* Draw the stars */&lt;br /&gt;    &lt;br /&gt;    drawStars();&lt;br /&gt;    &lt;br /&gt;    /* Swap the buffers */&lt;br /&gt;    &lt;br /&gt;    SDL_Flip(screen);&lt;br /&gt;    &lt;br /&gt;    /* Sleep briefly to stop sucking up all the CPU time */&lt;br /&gt;    &lt;br /&gt;    SDL_Delay(1);&lt;br /&gt;    &lt;br /&gt;    delay(frameLimit);&lt;br /&gt;    &lt;br /&gt;    frameLimit = SDL_GetTicks() + 16;&lt;br /&gt;}&lt;/pre&gt;First we position the stars before entering the main loop by calling &lt;span class="code"&gt;resetStars&lt;/span&gt;. Then, in our main loop, we call &lt;span class="code"&gt;doStars&lt;/span&gt; to update their positions and &lt;span class="code"&gt;drawStars&lt;/span&gt; to draw them. That's really all there is to it.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Now that we can accept user input, perform collision detection, use SDL_TTF to render text to the screen and animate sprites, we can put this all together to make a small game. We will do this in the next tutorial.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial09.tar.gz/download"&gt;tutorial09.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-2066608928393043637?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/2066608928393043637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-9-starfields.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/2066608928393043637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/2066608928393043637'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-9-starfields.html' title='Basic Game Tutorial #9 - Starfields'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-R0HPVxeARjA/ToDaN0lwKAI/AAAAAAAAAzA/e92Zzc0KURY/s72-c/tutorial09.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-4891081877531536973</id><published>2011-09-27T12:04:00.005-07:00</published><updated>2011-09-27T12:04:54.162-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='animation'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Basic Game Tutorial #8 - Sprites and Animation</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #8 - Sprites and Animation&lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;a href="http://3.bp.blogspot.com/-FQ24CiGPwzM/ToDaNgLOpbI/AAAAAAAAAy8/fcvNlf4V-VA/s1600/tutorial08.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-FQ24CiGPwzM/ToDaNgLOpbI/AAAAAAAAAy8/fcvNlf4V-VA/s320/tutorial08.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;An animating star&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=4891081877531536973" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;The easiest way to approach an animation is to think of it as a series of images that are shown one after the other. This tutorial will show you one way of achieving this.&lt;br /&gt;Compile and run tutorial08. The star will spin on the screen until the window is closed or Escape is pressed.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;We will start this tutorial by looking at the animation file, &lt;span class="code"&gt;data/anim/star.dat&lt;/span&gt;. The animation data file contains two lines. The first line is the number of frames in the animation and the rest are the names of the individual frames to load. This file is read by the &lt;span class="code"&gt;loadAnimation&lt;/span&gt; function in &lt;span class="code"&gt;animation.c&lt;/span&gt; which we will look at later. For the moment we will start with &lt;span class="code"&gt;structs.h&lt;/span&gt;. &lt;br /&gt;We define a structure for our animation as follows: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Animation&lt;br /&gt;{&lt;br /&gt;    int frameCount, frameIndex, counter;&lt;br /&gt;    SDL_Surface **frame;&lt;br /&gt;} Animation;&lt;/pre&gt;The &lt;span class="code"&gt;frameCount&lt;/span&gt; variable stores the number of frames in the Animation. &lt;span class="code"&gt;frameIndex&lt;/span&gt; is the frame number that we are currently indexing. &lt;span class="code"&gt;counter&lt;/span&gt; is the timer we will count down from before incrementing the &lt;span class="code"&gt;frameIndex&lt;/span&gt;. Finally &lt;span class="code"&gt;frame&lt;/span&gt; is an array of pointers to &lt;span class="code"&gt;SDL_Surface&lt;/span&gt;s. We will now look at the &lt;span class="code"&gt;animation.c&lt;/span&gt; file.   The &lt;span class="code"&gt;animation.c&lt;/span&gt; file contains 4 functions. As always, we will look at each one in turn. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void loadAnimation(char *name, Animation *anim)&lt;br /&gt;{&lt;br /&gt;    /* Load up the data file that describes the animation */&lt;br /&gt;    &lt;br /&gt;    int i;&lt;br /&gt;    FILE *fp = fopen(name, "rb");&lt;br /&gt;    char frameName[20];&lt;br /&gt;    &lt;br /&gt;    if (fp == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Failed to load animation file %s\n", name);&lt;br /&gt;        &lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Read the frame count */&lt;br /&gt;    &lt;br /&gt;    fscanf(fp, "%d", &amp;amp;anim-&amp;gt;frameCount);&lt;br /&gt;    &lt;br /&gt;    /* Allocate space for the animation */&lt;br /&gt;    &lt;br /&gt;    anim-&amp;gt;frame = (SDL_Surface **)malloc(anim-&amp;gt;frameCount * sizeof(SDL_Surface *));&lt;br /&gt;    &lt;br /&gt;    if (anim-&amp;gt;frame == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Ran out of memory when creating the animation for %s\n", name);&lt;br /&gt;        &lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Now load up each frame */&lt;br /&gt;    &lt;br /&gt;    for (i=0;iframeCount;i++)&lt;br /&gt;    {&lt;br /&gt;        fscanf(fp, "%s", frameName);&lt;br /&gt;        &lt;br /&gt;        anim-&amp;gt;frame[i] = loadImage(frameName);&lt;br /&gt;        &lt;br /&gt;        if (anim-&amp;gt;frame[i] == NULL)&lt;br /&gt;        {&lt;br /&gt;            printf("Failed to load animation frame %s\n", frameName);&lt;br /&gt;            &lt;br /&gt;            exit(1);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Set the initial frame index to 0 */&lt;br /&gt;    &lt;br /&gt;    anim-&amp;gt;frameIndex = 0;&lt;br /&gt;    &lt;br /&gt;    /* Set the animation counter */&lt;br /&gt;    &lt;br /&gt;    anim-&amp;gt;counter = ANIM_SPEED;&lt;br /&gt;}&lt;/pre&gt;The &lt;span class="code"&gt;loadAnimation&lt;/span&gt; function takes 2 parameters, the animation file to load and the address of the animation structure we wish to use. Firstly, we try and read the animation file and if this attempt fails then we flag the error and exit. Once we have successfully opened the file we read the first line of the file which is the number of frames in the animation and set this to the &lt;span class="code"&gt;frameCount&lt;/span&gt;. We then use this value to allocate the memory required for the frames. Again, if this fails then we flag the error and exit. Now we loop through the &lt;span class="code"&gt;frameCount&lt;/span&gt;, read the location of the image and load it using the &lt;span class="code"&gt;loadImage&lt;/span&gt; function. We then assign the image to the current frame of the animation. If any of the images fails to load the will log the error and exit. Once all the frames have been loaded, we assign the &lt;span class="code"&gt;frameIndex&lt;/span&gt; to 0, which is the first frame in the animation and set the &lt;span class="code"&gt;counter&lt;/span&gt; to &lt;span class="code"&gt;ANIM_SPEED&lt;/span&gt;.    &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void freeAnimation(Animation *anim)&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;    &lt;br /&gt;    /* Loop through each of the frames and free it */&lt;br /&gt;&lt;br /&gt;    if (anim-&amp;gt;frame != NULL)&lt;br /&gt;    {&lt;br /&gt;        for (i=0;i&amp;lt;anim-&amp;gt;frameCount;i++)&lt;br /&gt;        {&lt;br /&gt;            if (anim-&amp;gt;frame[i] != NULL)&lt;br /&gt;            {&lt;br /&gt;                SDL_FreeSurface(anim-&amp;gt;frame[i]);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        free(anim-&amp;gt;frame);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;freeAnimation works by simply looping through all of the frames in the animation and frees each one of them. We call this function once we are done with the animation.&lt;/span&gt;    Performing the animation is relatively straight forward: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doAnimation(Animation *anim)&lt;br /&gt;{&lt;br /&gt;    anim-&amp;gt;counter--;&lt;br /&gt;    &lt;br /&gt;    if (anim-&amp;gt;counter &amp;lt;= 0)&lt;br /&gt;    {&lt;br /&gt;        anim-&amp;gt;frameIndex++;&lt;br /&gt;        &lt;br /&gt;        if (anim-&amp;gt;frameIndex == anim-&amp;gt;frameCount)&lt;br /&gt;        {&lt;br /&gt;            anim-&amp;gt;frameIndex = 0;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        anim-&amp;gt;counter = ANIM_SPEED;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;doAnimation&lt;/span&gt; is the function which updates the frames in the animation. It does this by decrementing the &lt;span class="code"&gt;counter&lt;/span&gt; of the animation. When the counter reaches zero or less, we increase the &lt;span class="code"&gt;frameIndex&lt;/span&gt; of the animation. If our &lt;span class="code"&gt;frameIndex&lt;/span&gt; is equal to the animation's &lt;span class="code"&gt;frameCount&lt;/span&gt;, we set the &lt;span class="code"&gt;frameIndex&lt;/span&gt; back to 0 to continue to loop the animation. When we move another frame, we reset the &lt;span class="code"&gt;counter&lt;/span&gt; back to &lt;span class="code"&gt;ANIM_SPEED&lt;/span&gt;, which is defined in &lt;span class="code"&gt;defs.h&lt;/span&gt;.    The final function in this file draws the current animation frame: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void drawAnimation(Animation *anim, int x, int y)&lt;br /&gt;{&lt;br /&gt;    drawImage(anim-&amp;gt;frame[anim-&amp;gt;frameIndex], x, y);&lt;br /&gt;}&lt;/pre&gt;This function simply calls &lt;span class="code"&gt;drawImage&lt;/span&gt; function and passes in the surface of the animation's current &lt;span class="code"&gt;frameIndex&lt;/span&gt;.   In &lt;span class="code"&gt;graphics.c&lt;/span&gt;, we use the &lt;span class="code"&gt;updateScreen&lt;/span&gt; function to draw our animation to the screen. In &lt;span class="code"&gt;graphics.c&lt;/span&gt;, we call the &lt;span class="code"&gt;drawAnimation&lt;/span&gt; function as follows: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;drawAnimation(&amp;amp;starAnim, 288, 216);&lt;/pre&gt;We pass in the animation we wish to draw and render it to 288, 216 on the screen.    Finally, in &lt;span class="code"&gt;main.c&lt;/span&gt;, we load up the animation and update and draw it in our standard loop: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Load up the star animation */&lt;br /&gt;&lt;br /&gt;loadAnimation("data/anim/star.dat", &amp;amp;starAnim);&lt;br /&gt;&lt;br /&gt;/* Loop indefinitely for messages */&lt;br /&gt;&lt;br /&gt;while (go == 1)&lt;br /&gt;{&lt;br /&gt;    getInput();&lt;br /&gt;    &lt;br /&gt;    /* Update the animation frame */&lt;br /&gt;    &lt;br /&gt;    doAnimation(&amp;amp;starAnim);&lt;br /&gt;    &lt;br /&gt;    /* Draw the animation to the screen */&lt;br /&gt;    &lt;br /&gt;    updateScreen();&lt;br /&gt;    &lt;br /&gt;    /* Sleep briefly to stop sucking up all the CPU time */&lt;br /&gt;    &lt;br /&gt;    delay(frameLimit);&lt;br /&gt;    &lt;br /&gt;    frameLimit = SDL_GetTicks() + 16;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;The disadvantage to the way that we have done animation is that any game objects using this method will all animate in synchronization. This might not be a bad thing though, depending upon what you want to do. In another tutorial we will look at making game objects animate independently.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial08.tar.gz/download"&gt;tutorial08.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-4891081877531536973?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/4891081877531536973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-8-sprites-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4891081877531536973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4891081877531536973'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-8-sprites-and.html' title='Basic Game Tutorial #8 - Sprites and Animation'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-FQ24CiGPwzM/ToDaNgLOpbI/AAAAAAAAAy8/fcvNlf4V-VA/s72-c/tutorial08.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-3019876971646665647</id><published>2011-09-27T12:04:00.004-07:00</published><updated>2011-09-27T12:04:48.972-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='sdl_ttf'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Basic Game Tutorial #7 - SDL_TTF</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #7 - SDL_TTF&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 24pt; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-L-Kt_oB_TSA/ToDaNR4aauI/AAAAAAAAAy4/3DYJJ9dkMTA/s1600/tutorial07.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://4.bp.blogspot.com/-L-Kt_oB_TSA/ToDaNR4aauI/AAAAAAAAAy4/3DYJJ9dkMTA/s320/tutorial07.png" width="320" /&gt;&lt;/a&gt;&lt;span style="font-size: 14pt;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Displaying score using SDL_TTF&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;In this tutorial, we will look at SDL_TTF and how we can use it to display text on the screen.&lt;br /&gt;Compile and run tutorial07. You can control the ship by using the arrow keys (not the ones on the numeric pad). Pressing the space key will fire a bullet, which will move to the right from the ship's current position. If the bullet hits one of the UFOs then both it and the UFO will be removed. The bullet will also be removed if it goes past the right edge of the screen. Whenever you destroy a UFO, your score will increase by 100.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;A lot of the code has remained the same, so we will go through the files that have changed starting with &lt;span class="code"&gt;defs.h&lt;/span&gt; &lt;br /&gt;SDL_TTF requires the SDL_TTF.h include, so we add it here &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;#include "SDL/SDL_ttf.h"&lt;/pre&gt;Now that we have done this we can look at &lt;span class="code"&gt;structs.h&lt;/span&gt;   We have added a new structure called &lt;span class="code"&gt;game&lt;/span&gt; to store the score, screen and font: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Game&lt;br /&gt;{&lt;br /&gt;    int score;&lt;br /&gt;    SDL_Surface *screen;&lt;br /&gt;    TTF_Font *font;&lt;br /&gt;} Game;&lt;/pre&gt;The &lt;span class="code"&gt;font&lt;/span&gt; will be loaded up later on in &lt;span class="code"&gt;font.c&lt;/span&gt;.    Like &lt;span class="code"&gt;SDL_Mixer&lt;/span&gt;, SDL_TTF must be initialised and closed after we have used it. We perform both these calls in &lt;span class="code"&gt;init.c&lt;/span&gt;. In our &lt;span class="code"&gt;init&lt;/span&gt; function we initialise SDL_TTF: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (TTF_Init() &amp;lt; 0)&lt;br /&gt;{&lt;br /&gt;    printf("Couldn't initialize SDL TTF: %s\n", SDL_GetError());&lt;br /&gt;&lt;br /&gt;    exit(1);&lt;br /&gt;}&lt;/pre&gt;The code should be self explanitory. In our &lt;span class="code"&gt;cleanup&lt;/span&gt; function, we need to close the font in the same way that have to free music and surfaces: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Close the font */&lt;br /&gt;&lt;br /&gt;closeFont(game.font);&lt;/pre&gt;We will look at this function later. We also need to close SDL_TTF which we do after we have closed all used fonts: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;/* Close SDL_TTF */&lt;br /&gt;&lt;br /&gt;TTF_Quit();&lt;/pre&gt;Now that we have dealt with initialising and closing the library, we will look at loading and displaying a font on the screen.    &lt;span class="code"&gt;font.c&lt;/span&gt; contains 3 functions which we will look at one at a time. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;TTF_Font *loadFont(char *name, int size)&lt;br /&gt;{&lt;br /&gt;    /* Use SDL_TTF to load the font at the specified size */&lt;br /&gt;    &lt;br /&gt;    TTF_Font *font = TTF_OpenFont(name, size);&lt;br /&gt;&lt;br /&gt;    if (font == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Failed to open Font %s: %s\n", name, TTF_GetError());&lt;br /&gt;&lt;br /&gt;        exit(1);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return font;&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;loadFont&lt;/span&gt; takes 2 arguments, the filename of the file to load and the size of the font to create, in pt. We call the SDL_TTF function &lt;span class="code"&gt;TTF_OpenFont&lt;/span&gt;, passing in the filename and the size which will return a &lt;span class="code"&gt;TTF_Font&lt;/span&gt;. As always, we verify that the font was loaded correctly before we continue. If not, then we will exit. Otherwise we return the newly created font. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void closeFont(TTF_Font *font)&lt;br /&gt;{&lt;br /&gt;    /* Close the font once we're done with it */&lt;br /&gt;    &lt;br /&gt;    if (font != NULL)&lt;br /&gt;    {&lt;br /&gt;        TTF_CloseFont(font);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;span class="code"&gt;closeFont&lt;/span&gt; is quite simple, we pass in the font we wish to close and pass it to &lt;span class="code"&gt;TTF_CloseFont&lt;/span&gt;, provided that it is not &lt;span class="code"&gt;NULL&lt;/span&gt;. The final, and longest function in the file, deals with rendering a String to the screen: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void drawString(char *text, int x, int y, TTF_Font *font, int centerX, int centerY)&lt;br /&gt;{&lt;br /&gt;    SDL_Rect dest;&lt;br /&gt;    SDL_Surface *surface;&lt;br /&gt;    SDL_Color foregroundColor, backgroundColor;&lt;br /&gt;    &lt;br /&gt;    /* White text on a black background */&lt;br /&gt;    &lt;br /&gt;    foregroundColor.r = 255;&lt;br /&gt;    foregroundColor.g = 255;&lt;br /&gt;    foregroundColor.b = 255;&lt;br /&gt;    &lt;br /&gt;    backgroundColor.r = 0;&lt;br /&gt;    backgroundColor.g = 0;&lt;br /&gt;    backgroundColor.b = 0;&lt;br /&gt;    &lt;br /&gt;    /* Use SDL_TTF to generate a string image, this returns an SDL_Surface */&lt;br /&gt;&lt;br /&gt;    surface = TTF_RenderUTF8_Shaded(font, text, foregroundColor, backgroundColor);&lt;br /&gt;&lt;br /&gt;    if (surface == NULL)&lt;br /&gt;    {&lt;br /&gt;        printf("Couldn't create String %s: %s\n", text, SDL_GetError());&lt;br /&gt;&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /* Blit the entire surface to the screen */&lt;br /&gt;&lt;br /&gt;    dest.x = (centerX == 1 ? (game.screen-&amp;gt;w - surface-&amp;gt;w) / 2 : x);&lt;br /&gt;    dest.y = (centerY == 1 ? (game.screen-&amp;gt;h - surface-&amp;gt;h) / 2 : y);&lt;br /&gt;    dest.w = surface-&amp;gt;w;&lt;br /&gt;    dest.h = surface-&amp;gt;h;&lt;br /&gt;&lt;br /&gt;    SDL_BlitSurface(surface, NULL, game.screen, &amp;amp;dest);&lt;br /&gt;    &lt;br /&gt;    /* Free the generated string image */&lt;br /&gt;&lt;br /&gt;    SDL_FreeSurface(surface);&lt;br /&gt;}&lt;/pre&gt;The &lt;span class="code"&gt;drawString&lt;/span&gt; function takes 6 arguments, the String to be printed, the x and y coordindates of the String, the font to use and whether or not to center it horizontally and vertically on the screen respectively. The function &lt;span class="code"&gt;TTF_RenderUTF8_Shaded&lt;/span&gt; function takes 4 arguments, the font to use, String to print and the foreground and background colours. The colours are &lt;span class="code"&gt;SDL_Color&lt;/span&gt; structures and we set the &lt;span class="code"&gt;r&lt;/span&gt;, &lt;span class="code"&gt;g&lt;/span&gt; and &lt;span class="code"&gt;b&lt;/span&gt; values of the &lt;span class="code"&gt;foregroundColor&lt;/span&gt; to 255, which is white. We set the &lt;span class="code"&gt;backgroundColor&lt;/span&gt; to black, indicated by 0. This function will then return an &lt;span class="code"&gt;SDL_Surface&lt;/span&gt; which we can blit to screen as usual. If the rendering fails for any reason then a &lt;span class="code"&gt;NULL&lt;/span&gt; surface will be returned. If the &lt;span class="code"&gt;centerX&lt;/span&gt; or &lt;span class="code"&gt;centerY&lt;/span&gt; variables are set then we center the surface on the screen respectively, by taking substracting the width (or height) of the surface from the width (or height) of the screen and then halving the result. When we have blitted the surface to the screen we must free it afterwards, by calling &lt;span class="code"&gt;SDL_FreeSurface&lt;/span&gt;. We will call &lt;span class="code"&gt;drawString&lt;/span&gt; in the &lt;span class="code"&gt;draw&lt;/span&gt; function.   In &lt;span class="code"&gt;main.c&lt;/span&gt;, we call the &lt;span class="code"&gt;loadFont&lt;/span&gt; function.&lt;br /&gt;We have also added made a slight change to &lt;span class="code"&gt;collisions.c&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (collision(entity[i].x, entity[i].y, entity[i].sprite-&amp;gt;w, entity[i].sprite-&amp;gt;h,&lt;br /&gt;entity[j].x, entity[j].y, entity[j].sprite-&amp;gt;w, entity[j].sprite-&amp;gt;h) == 1)&lt;br /&gt;{&lt;br /&gt;    /* If a collision occured, remove both Entities */&lt;br /&gt;    &lt;br /&gt;    entity[j].active = 0;&lt;br /&gt;    &lt;br /&gt;    entity[i].active = 0;&lt;br /&gt;    &lt;br /&gt;    /* Add 100 points to the score */&lt;br /&gt;    &lt;br /&gt;    game.score += 100;&lt;br /&gt;}&lt;/pre&gt;When a UFO is destroyed, we add 100 points to our &lt;span class="code"&gt;score&lt;/span&gt; variable in our &lt;span class="code"&gt;game&lt;/span&gt; structure. We will now look at our drawing function to see how the score is displayed on the screen.   &lt;br /&gt;To generate the score text, we need to create a String from our score. We can do this easily using the C function &lt;span class="code"&gt;sprintf&lt;/span&gt;. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;char text[20];&lt;br /&gt;&lt;br /&gt;/* Blank the screen */&lt;br /&gt;&lt;br /&gt;SDL_FillRect(game.screen, NULL, 0);&lt;br /&gt;&lt;br /&gt;/* Draw the score */&lt;br /&gt;&lt;br /&gt;sprintf(text, "SCORE: %05d", game.score);&lt;br /&gt;&lt;br /&gt;drawString(text, 100, 10, game.font, 1, 0);&lt;/pre&gt;Now that we have created a String, we can call &lt;span class="code"&gt;drawString&lt;/span&gt; to render the text to 100, 10. Note though that since our 5th argument is set to 1, we want to center the score horizontally so the value of 100 will actually be ignored.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Conclusion"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;SDL_TTF has many ways of rendering text, ranging from quick and dirty to slow and beautiful. You can view the API by clicking on &lt;a href="http://jcatki.no-ip.org:8080/SDL_ttf/SDL_ttf_frame.html"&gt;this link&lt;/a&gt;. &lt;br /&gt;In the next tutorial we will look at one way of doing animation in SDL. &lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial07.tar.gz/download"&gt;tutorial07.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-3019876971646665647?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/3019876971646665647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-7-sdlttf.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/3019876971646665647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/3019876971646665647'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-7-sdlttf.html' title='Basic Game Tutorial #7 - SDL_TTF'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-L-Kt_oB_TSA/ToDaNR4aauI/AAAAAAAAAy4/3DYJJ9dkMTA/s72-c/tutorial07.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-8451417465164718146</id><published>2011-09-27T12:04:00.003-07:00</published><updated>2011-12-09T12:11:48.947-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='collision detection'/><title type='text'>Basic Game Tutorial #6 - Collision Detection</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #6 - Collision Detection&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-SMnhd0YNeSI/ToDaM6bYuoI/AAAAAAAAAy0/cshBwksfBWE/s1600/tutorial06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://4.bp.blogspot.com/-SMnhd0YNeSI/ToDaM6bYuoI/AAAAAAAAAy0/cshBwksfBWE/s320/tutorial06.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Collision Detection&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;Collision detection is a vital part of any game. In this tutorial we will look at 2D collision detection so that you can fire a bullet and make it hit an enemy UFO.&lt;br /&gt;Compile and run tutorial06. You can control the ship by using the arrow keys (not the ones on the numeric pad). Pressing the space key will fire a bullet, which will move to the right from the ship's current position. If the bullet hits one of the UFOs then both it and the UFO will be removed. The bullet will also be removed if it goes past the right edge of the screen.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;Most of the code has not changed very much, so we will only look at the functions that have changed or that are new. We will start will &lt;span class="code"&gt;structs.h&lt;/span&gt;&lt;br /&gt;We update the Entity structure by adding another variable called &lt;span class="code"&gt;type&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Entity&lt;br /&gt;{&lt;br /&gt;    int active, type;&lt;br /&gt;    int x, y, thinkTime;&lt;br /&gt;    SDL_Surface *sprite;&lt;br /&gt;    void (*action)(void);&lt;br /&gt;    void (*draw)(void);&lt;br /&gt;} Entity;&lt;/pre&gt;The &lt;span class="code"&gt;type&lt;/span&gt; variable will be used in the collision detection routine, since we don't  want bullets to collide against each other.    In &lt;span class="code"&gt;main.c&lt;/span&gt;, we call two new functions &lt;span class="code"&gt;addUFO&lt;/span&gt; and &lt;span class="code"&gt;doCollisions&lt;/span&gt;. These two functions will be looked at later on. &lt;br /&gt;We have made a minor change to &lt;span class="code"&gt;bullet.c&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;entity[i].x = x;&lt;br /&gt;entity[i].y = y;&lt;br /&gt;entity[i].action = &amp;amp;moveStandardBullet;&lt;br /&gt;entity[i].draw = &amp;amp;drawStandardEntity;&lt;br /&gt;entity[i].sprite = getSprite(BULLET_SPRITE);&lt;br /&gt;entity[i].type = TYPE_BULLET;&lt;/pre&gt;We set the Entity type to &lt;span class="code"&gt;TYPE_BULLET&lt;/span&gt;. This helps us identify the Entity as being a bullet so that we don't try and collide bullets against each other.    The new file &lt;span class="code"&gt;ufo.c&lt;/span&gt;, contains all the code for dealing with the UFOs. There are only two functions in this file and it is essentially the same as &lt;span class="code"&gt;bullet.c&lt;/span&gt;: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;int i = getFreeEntity();&lt;br /&gt;&lt;br /&gt;if (i == -1)&lt;br /&gt;{&lt;br /&gt;    printf("Couldn't get a free slot for a UFO!\n");&lt;br /&gt; &lt;br /&gt;    return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;entity[i].x = x;&lt;br /&gt;entity[i].y = y;&lt;br /&gt;entity[i].action = &amp;amp;moveUFO;&lt;br /&gt;entity[i].draw = &amp;amp;drawStandardEntity;&lt;br /&gt;entity[i].sprite = getSprite(UFO_SPRITE);&lt;br /&gt;entity[i].type = TYPE_ENEMY;&lt;/pre&gt;As in the &lt;span class="code"&gt;bullet.c&lt;/span&gt;, we get search for a free Entity to assign to our UFO and set its functions. The &lt;span class="code"&gt;moveUFO&lt;/span&gt; function is below, but it is an empty function, essentially meaning that the UFO will do nothing. Finally, we set the Entity type to &lt;span class="code"&gt;TYPE_ENEMY&lt;/span&gt;.   &lt;br /&gt;Now we will look at the collision detection. This function is located in &lt;span class="code"&gt;collisions.c&lt;/span&gt;. We will start by looking at the actual detection routine itself: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;int collision(int x0, int y0, int w0, int h0, int x2, int y2, int w1, int h1)&lt;br /&gt;{&lt;br /&gt;    int x1 = x0 + w0;&lt;br /&gt;    int y1 = y0 + h0;&lt;br /&gt;&lt;br /&gt;    int x3 = x2 + w1;&lt;br /&gt;    int y3 = y2 + h1;&lt;br /&gt;&lt;br /&gt;    return !(x1&amp;lt;x2 || x3&amp;lt;x0 || y1&amp;lt;y2 || y3&amp;lt;y0);&lt;br /&gt;}&lt;/pre&gt;The 2D collision detection routine is box to box, which is not accurate, but it is very fast. There are routines for pixel perfect collision detection, but we will not be looking at these. This function takes 8 parameters, the x, y, width and height of the first box and the x, y, width and height of the second box. Using these parameters we then construct the coordinates of two rectangles and test if they overlap. The function will return 1 if they do and 0 if they don't. We will now look at its use: &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void doCollisions()&lt;br /&gt;{&lt;br /&gt;    int i, j;&lt;br /&gt;&lt;br /&gt;    /* Check each entity against the rest, skipping over inactive ones */&lt;br /&gt;&lt;br /&gt;    for (i=0;i&amp;lt;MAX_ENTITIES;i++)&lt;br /&gt;    {&lt;br /&gt;        if (entity[i].active == 0)&lt;br /&gt;        {&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        for (j=0;j&amp;lt;MAX_ENTITIES;j++)&lt;br /&gt;        {&lt;br /&gt;            /* Don't collide with yourself, inactive entities or entities of the same type */&lt;br /&gt;            &lt;br /&gt;            if (i == j || entity[j].active == 0 || entity[j].type == entity[i].type)&lt;br /&gt;            {&lt;br /&gt;                continue;&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            /* Test the collision */&lt;br /&gt;&lt;br /&gt;            if (collision(entity[i].x, entity[i].y, entity[i].sprite-&amp;gt;w, entity[i].sprite-&amp;gt;h,&lt;br /&gt;            entity[j].x, entity[j].y, entity[j].sprite-&amp;gt;w, entity[j].sprite-&amp;gt;h) == 1)&lt;br /&gt;            {&lt;br /&gt;                /* If a collision occured, remove both Entities */&lt;br /&gt;                &lt;br /&gt;                entity[j].active = 0;&lt;br /&gt;                &lt;br /&gt;                entity[i].active = 0;&lt;br /&gt;                &lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;In &lt;span class="code"&gt;doCollisions&lt;/span&gt; we run two loops, one inside the other, since we need to check each Entity against all the others. In our outer loop, we first check that the Entity we are indexing is actually active, otherwise we simply pass over it. Then, in our inner loop, we skip over any Entity that is either the same type as the current Entity, is no active or is Entity that we are currently checking. We then run our collision test by passing in the x, y, width and height of both Entities and checking the response. If we get back a value of 1 then we set both the Entities to inactive and break out of the inner loop.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;So now you know how to move a sprite, fire a bullet and make it hit something. In later tutorials we will look at a health system so that when something is hit it doesn't die straight away, but you could always try this yourself. The theory is very simple: add a additional variable to the &lt;span class="code"&gt;Entity&lt;/span&gt; structure to store the health. When a collison occurs you decrease the health and if it is less than or equal to 0 you remove the Entity. &lt;br /&gt;In the next tutorial we will look at SDL_TTF so that we can display information such as the player's score.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial06.tar.gz/download"&gt;tutorial06.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-8451417465164718146?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/8451417465164718146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-6-collision.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/8451417465164718146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/8451417465164718146'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-6-collision.html' title='Basic Game Tutorial #6 - Collision Detection'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-SMnhd0YNeSI/ToDaM6bYuoI/AAAAAAAAAy0/cshBwksfBWE/s72-c/tutorial06.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-4692534268454870151</id><published>2011-09-27T12:04:00.002-07:00</published><updated>2011-09-27T12:04:36.910-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='bullet'/><title type='text'>Basic Game Tutorial #5 - Firing bullets</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #5 - Firing bullets&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 24pt; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-49nYcIMGf4I/ToDaMk_J2hI/AAAAAAAAAyw/prPZC2rzMh4/s1600/tutorial05.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-49nYcIMGf4I/ToDaMk_J2hI/AAAAAAAAAyw/prPZC2rzMh4/s320/tutorial05.png" width="320" /&gt;&lt;/a&gt;&lt;span style="font-size: 14pt;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Firing bullets&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=4692534268454870151" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;Now that we can move a sprite around the screen, we will look into firing bullets. These tutorials will go into less detail about loading images and sounds because they have been covered in earlier tutorials and the theory is essentially the same.&lt;br /&gt;Compile and run tutorial05. You can control the ship by using the arrow keys (not the ones on the numeric pad). Pressing the space key will fire a bullet, which will move to the right from the ship's current position. &lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=4692534268454870151" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;To deal with the player and the bullets, we update the Entity structure as follows:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;typedef struct Entity&lt;br /&gt;{&lt;br /&gt;    int active;&lt;br /&gt;    int x, y, thinkTime;&lt;br /&gt;    SDL_Surface *sprite;&lt;br /&gt;    void (*action)(void);&lt;br /&gt;    void (*draw)(void);&lt;br /&gt;} Entity;&lt;/pre&gt;We will be creating an array of Entities so the easiest way to determine whether an Entity is being used is to set a variable stating this. If the &lt;span class="code"&gt;active&lt;/span&gt; variable is 0 then this Entity is not being used and can therefore be used to create a new bullet or whatever we want to create from it. The &lt;span class="code"&gt;thinkTime&lt;/span&gt; variable is a timer that, in this tutorial is used to limit the number of bullets we can fire per second. &lt;span class="code"&gt;action&lt;/span&gt; and &lt;span class="code"&gt;draw&lt;/span&gt; are simply function pointers to our action and drawing functions respectively.   &lt;br /&gt;The &lt;span class="code"&gt;Control&lt;/span&gt; function has another value, &lt;span class="code"&gt;fire&lt;/span&gt; which is used to let us know that we want to attempt to fire a bullet. &lt;br /&gt;We will first look at &lt;span class="code"&gt;entites.c&lt;/span&gt;. This file has 5 functions in it. We will look at these one at a time. &lt;br /&gt;The &lt;span class="code"&gt;clearEntities&lt;/span&gt; function loops through all of the available Entities and marks them as inactive using the C function &lt;span class="code"&gt;memset&lt;/span&gt;. This ensures that at the start of the program, there are empty slots to fire bullets. In a larger game you would need to reset everything at the start of a level to make sure that when it starts there aren't enemies, bullets etc. appearing randomly on the screen.  &lt;br /&gt;&lt;span class="code"&gt;getFreeEntity&lt;/span&gt; is a function that will be commonly used. It will loop through all the available Entities and return the index of the first one it finds that is marked as inactive. It will also initialise the Entity to ensure that all of its variables and functions are set to 0. If the function cannot find a free Entity, it will return -1 and you would deal with it as appropriate. In our code we will simply flag an error and carry on. &lt;br /&gt;&lt;span class="code"&gt;doEntities&lt;/span&gt; is used in the main game loop. This function loops through all the Entities and point its memory address to the &lt;span class="code"&gt;self&lt;/span&gt; Entity global pointer, which we will go into more detail later on. If the Entity is marked as active, we call its &lt;span class="code"&gt;action&lt;/span&gt; function. &lt;br /&gt;&lt;span class="code"&gt;drawEntities&lt;/span&gt; is exactly the same as &lt;span class="code"&gt;doEntities&lt;/span&gt;, except that we call the &lt;span class="code"&gt;draw&lt;/span&gt; function instead. &lt;br /&gt;The &lt;span class="code"&gt;drawStandardEntity&lt;/span&gt; function is similar to the &lt;span class="code"&gt;drawPlayer&lt;/span&gt; functions from previous tutorials. Note that we are using the &lt;span class="code"&gt;self&lt;/span&gt; pointer in this function. You will see how this is used later. &lt;br /&gt;In &lt;span class="code"&gt;input.c&lt;/span&gt; we add add the reading of the space key to the inputs. &lt;br /&gt;We'll now look at &lt;span class="code"&gt;player.c&lt;/span&gt;, specifically the &lt;span class="code"&gt;doPlayer&lt;/span&gt; function. At the start of the function we decrease the player's thinkTime, and if it is less than or equal to 0, we set it to 0.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;player.thinkTime--;&lt;br /&gt;&lt;br /&gt;if (player.thinkTime &amp;lt;= 0)&lt;br /&gt;{&lt;br /&gt;    player.thinkTime = 0;&lt;br /&gt;}&lt;/pre&gt;The &lt;span class="code"&gt;thinkTime&lt;/span&gt; is what controls the player's ability to fire bullets. We constantly decrease this value in each loop until it reaches 0. We must stop it from simply decreasing continously as the integer value would eventually wrap around and then the player would not be able to fire a bullet for a very long time (since it would then become positive again). The rest of the code is the same apart from the reading of the fire button:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (input.fire == 1)&lt;br /&gt;{&lt;br /&gt;    /* You can only fire when the thinkTime is 0 or less */&lt;br /&gt;    &lt;br /&gt;    if (player.thinkTime &amp;lt;= 0)&lt;br /&gt;    {&lt;br /&gt;        addBullet(player.x + player.sprite-&amp;gt;w, player.y + (player.sprite-&amp;gt;h / 2));&lt;br /&gt;        &lt;br /&gt;        player.thinkTime = MAX_RELOAD_TIME;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;When the program detects the space key, it will then attempt to fire a bullet. A bullet can only be fired if the &lt;span class="code"&gt;thinkTime&lt;/span&gt; is 0 or less, so if this is true the we call the &lt;span class="code"&gt;addBullet&lt;/span&gt; function. This function takes the starting x and y coordinates, which we set to the right hand side of the player's sprite and roughly halfway down the player's height respectively. We will look into this function in more detail later. Once we have fired a bullet, we set the &lt;span class="code"&gt;thinkTime&lt;/span&gt; back to the &lt;span class="code"&gt;MAX_RELOAD_TIME&lt;/span&gt;, otherwise the player would be able to fire again immediately afterwards. The lower the value is for &lt;span class="code"&gt;MAX_RELOAD_TIME&lt;/span&gt;, the sooner the player will be able to fire another bullet. The inverse is also true, so try changing this value to see what happens. It is in &lt;span class="code"&gt;defs.h&lt;/span&gt;.   &lt;br /&gt;&lt;span class="code"&gt;bullet.c&lt;/span&gt; handles the creation and movement of the bullets. We will look at each of the functions in this file in turn:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;void addBullet(int x, int y)&lt;br /&gt;{&lt;br /&gt;    int i = getFreeEntity();&lt;br /&gt;    &lt;br /&gt;    if (i == -1)&lt;br /&gt;    {&lt;br /&gt;        printf("Couldn't get a free slot for a bullet!\n");&lt;br /&gt;        &lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    entity[i].x = x;&lt;br /&gt;    entity[i].y = y;&lt;br /&gt;    entity[i].action = &amp;amp;moveStandardBullet;&lt;br /&gt;    entity[i].draw = &amp;amp;drawStandardEntity;&lt;br /&gt;    entity[i].sprite = getSprite(BULLET_SPRITE);&lt;br /&gt;    &lt;br /&gt;    /* Play a sound when the shot is fired */&lt;br /&gt;    &lt;br /&gt;    playSound(BULLET_SOUND);&lt;br /&gt;}&lt;/pre&gt;The &lt;span class="code"&gt;addBullet&lt;/span&gt; function first gets a free Entity by calling the &lt;span class="code"&gt;getFreeEntity&lt;/span&gt; function. If we get back -1 then we ran out of Entities to create bullets from so we will just log the error to the console and return. Using the index number we get back we set the Entity's &lt;span class="code"&gt;x&lt;/span&gt; and &lt;span class="code"&gt;y&lt;/span&gt; using the values passed in. For the &lt;span class="code"&gt;action&lt;/span&gt;, we set this to the &lt;span class="code"&gt;moveStandardBullet&lt;/span&gt; function found later on in this file. We use &lt;span class="code"&gt;drawStandardEntity&lt;/span&gt; for the &lt;span class="code"&gt;draw&lt;/span&gt; function which we covered earlier in the tutorial. We also set the sprite to the &lt;span class="code"&gt;BULLET_SPRITE&lt;/span&gt;. Finally, we call the &lt;span class="code"&gt;playSound&lt;/span&gt; function to play the sound of a bullet being fired. &lt;br /&gt;The second function, &lt;span class="code"&gt;moveStandardBullet&lt;/span&gt; is the function called when the bullet's &lt;span class="code"&gt;action&lt;/span&gt; function is called. Note that we use the &lt;span class="code"&gt;self&lt;/span&gt; pointer which means that we don't need to track the Entity itself and we can also manipulate the values without having to return anything.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;static void moveStandardBullet()&lt;br /&gt;{&lt;br /&gt;    /* Move the bullet across the screen */&lt;br /&gt;    &lt;br /&gt;    self-&amp;gt;x += BULLET_SPEED;&lt;br /&gt;    &lt;br /&gt;    /* Kill the bullet if it moves off the screen */&lt;br /&gt;    &lt;br /&gt;    if (self-&amp;gt;x &amp;gt;= SCREEN_WIDTH)&lt;br /&gt;    {&lt;br /&gt;        self-&amp;gt;active = 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The function is simple enough, the bullet will move at the speed defined by &lt;span class="code"&gt;BULLET_SPEED&lt;/span&gt; and once it reaches the edge of the screen, it will be marked as inactive, by setting its &lt;span class="code"&gt;active&lt;/span&gt; variable to 0. Since we are moving from left to right, we need to check the position of the left edge of the sprite to prevent it from being made inactive prematurely.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=4692534268454870151" name="Conclusion"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Like the previous tutorial, firing a basic bullet is quite simple. In the next tutorial, we will look into collision detection.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=4692534268454870151" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial05.tar.gz/download"&gt;tutorial05.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-4692534268454870151?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/4692534268454870151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-5-firing-bullets.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4692534268454870151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4692534268454870151'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-5-firing-bullets.html' title='Basic Game Tutorial #5 - Firing bullets'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-49nYcIMGf4I/ToDaMk_J2hI/AAAAAAAAAyw/prPZC2rzMh4/s72-c/tutorial05.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-313223966295810607</id><published>2011-09-27T12:04:00.001-07:00</published><updated>2011-09-27T12:04:30.968-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='sprite'/><title type='text'>Basic Game Tutorial #4 - Controlling a sprite</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #4 - Controlling a sprite&lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;a href="http://1.bp.blogspot.com/-BWdkJSqyCmI/ToDaMJW6GqI/AAAAAAAAAys/sOqzSJ_Js-U/s1600/tutorial04.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="253" src="http://1.bp.blogspot.com/-BWdkJSqyCmI/ToDaMJW6GqI/AAAAAAAAAys/sOqzSJ_Js-U/s320/tutorial04.png" width="320" /&gt;&lt;/a&gt;&lt;a href="http://reddwarf.local/images/tutorials/tutorial04.png"&gt; &lt;/a&gt;&lt;/td&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;Moving a sprite&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=313223966295810607" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;This tutorial will demonstrate how to move a loaded image around a screen. This tutorial uses the keyboard for the input but future tutorials will explain how to use the joystick.&lt;br /&gt;Compile and run tutorial04. You can control the ship by using the arrow keys (not the ones on the numeric pad). The ship is constrained to the bounds of the window.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=313223966295810607" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;The &lt;span class="code"&gt;defs.h&lt;/span&gt; now contains an enumeration which will be used to store the sprites used in the program. This makes storing and referencing them a lot easier. Currently though there is only one sprite that is loaded, &lt;span class="code"&gt;PLAYER_SPRITE&lt;/span&gt;, but more will be loaded in future tutorials.  A new structure has been added to &lt;span class="code"&gt;structs.h&lt;/span&gt;. The &lt;span class="code"&gt;Entity&lt;/span&gt; structure allows us to store the coordinates of the ship as well as a pointer to its image. We also add another structure &lt;span class="code"&gt;Control&lt;/span&gt; which we will use to store the inputs for our directions.&lt;br /&gt;In &lt;span class="code"&gt;main.c&lt;/span&gt; we call &lt;span class="code"&gt;loadAllSprites&lt;/span&gt; to load up all of the sprites that we will use in the program and then initialise the player by calling &lt;span class="code"&gt;initPlayer&lt;/span&gt;, which sets the player's sprite and also centers the player to the middle of the screen. We then enter the main loop and call &lt;span class="code"&gt;getInput&lt;/span&gt; to collect the input keys that are pressed followed by &lt;span class="code"&gt;doPlayer&lt;/span&gt; which handles the player's movement on the screen. &lt;span class="code"&gt;draw&lt;/span&gt; simply draws the player's sprite to the screen. Finally, to allow smooth movement of the sprite on the screen, we limit the number of frames per second to 60. At the start of the main function, we create an unsigned int called &lt;span class="code"&gt;frameLimit&lt;/span&gt;  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;unsigned int frameLimit = SDL_GetTicks() + 16;&lt;/pre&gt;The function &lt;span class="code"&gt;SDL_GetTicks&lt;/span&gt; gets the number of milliseconds that have passed since SDL was initialised. The value of 16 will allow us to limit the number of frames to 60, since 1000 / 60 = 16. After we call &lt;span class="code"&gt;frameLimit&lt;/span&gt; we set the next frame limit to the current ticks + 16 again:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;frameLimit = SDL_GetTicks() + 16;&lt;/pre&gt;In &lt;span class="code"&gt;input.c&lt;/span&gt; add code to read the up, down, left and right arrow keys on the keyboard. We detect that the up arrow on the keyboard has been pressed with the following code:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;case SDLK_UP:&lt;br /&gt;    input.up = 1;&lt;br /&gt;break;&lt;/pre&gt;This sets the up variable in our &lt;span class="code"&gt;Control&lt;/span&gt; structure to 1. We will read this value later on to test if we need to move the player's sprite up the screen. The reason why we store this value instead of just moving the player's sprite immediately is because of keyboard repeat delay. Just like when you are typing, if you hold down a key, the letter will be printed, followed by a delay and then the letter will be printed repeatedly depending upon your keyboard's repeat rate and delay, which is not desirable. When the key is released, we will set the up variable in the structure to 0:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;case SDLK_UP:&lt;br /&gt;    input.up = 0;&lt;br /&gt;break;&lt;/pre&gt;The process for detecting the left, right and down key presses are the same, so we will not cover these.  &lt;br /&gt;&lt;span class="code"&gt;player.c&lt;/span&gt; contains three functions, &lt;span class="code"&gt;initPlayer&lt;/span&gt;, &lt;span class="code"&gt;doPlayer&lt;/span&gt; and &lt;span class="code"&gt;drawPlayer&lt;/span&gt;. We have already covered what &lt;span class="code"&gt;initPlayer&lt;/span&gt; does, so we will look at &lt;span class="code"&gt;drawPlayer&lt;/span&gt;. We take the values set in our &lt;span class="code"&gt;control&lt;/span&gt; structure and test them one at a time.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (input.up == 1)&lt;br /&gt;{&lt;br /&gt;    player.y -= 3;&lt;br /&gt;&lt;br /&gt;    /* Don't allow the player to move off the screen */&lt;br /&gt;&lt;br /&gt;    if (player.y &amp;lt; 0)&lt;br /&gt;    {&lt;br /&gt;        player.y = 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;The above code will test if the up variable in our structure has been set to 1 and if it has then we will move the player's sprite 3 pixels up the screen. We need to prevent the player from being able to move off the top of the screen however, but this is quite simple. The top most pixel of the screen is 0, like in arrays and the player's sprite is drawn from the top left corner, so we just check to see if the player's position is less than 0 and if it is then we set it to 0. Preventing the player from moving off the bottom of the screen is similar, we just need to take some more details into account. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (input.down == 1)&lt;br /&gt;{&lt;br /&gt;    player.y += 3;&lt;br /&gt;&lt;br /&gt;    /* Don't allow the player to move off the screen */&lt;br /&gt;&lt;br /&gt;    if (player.y + player.sprite-&amp;gt;h &amp;gt;= SCREEN_HEIGHT)&lt;br /&gt;    {&lt;br /&gt;        player.y = SCREEN_HEIGHT - (player.sprite-&amp;gt;h + 1);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;To stop the player from moving off the bottom of the screen, we need to includes the sprite's height in our check. Since the screen coordinates start at 0, the screen height will be 1 unit less, so if the player's y coordinate plus its height is greater than or equal to the screen's height then the player's sprite has left the screen. To correct this, we need to move the ship as close to the edge of the screen as possible without going over it, so we place the player's y coordinate at the screen's height and then subtract the sprite's height. Since the screen coordinates start at 0 though we are still 1 pixel over so we need to move 1 additional pixel up to correct this. Logic for the movement of the x coordinate is the same, except we check the sprite's width rather than its height.   After all of this, the &lt;span class="code"&gt;drawPlayer&lt;/span&gt; function simply calls the &lt;span class="code"&gt;drawImage&lt;/span&gt; function, that we have used in previous tutorials, to draw the player's sprite to the screen. &lt;br /&gt;Finally, we will look at the drawing. &lt;span class="code"&gt;draw.c&lt;/span&gt; contains two functions. The &lt;span class="code"&gt;draw&lt;/span&gt; function blanks the screen, draws the player and swaps the buffers. We also sleep briefly to return some time back to the CPU. The second function, &lt;span class="code"&gt;delay&lt;/span&gt;, limits the program's speed to 60 frames per second. Firstly, we pass in the desired tick time, which is how many ticks need to have passed before we can continue. We then get the current ticks:  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;unsigned int ticks = SDL_GetTicks();&lt;/pre&gt;Now we check to see if the tired tick time is in the past.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (frameLimit &amp;lt; ticks)&lt;br /&gt;{&lt;br /&gt;    return;&lt;br /&gt;}&lt;/pre&gt;If this happens then we can continue with the program without any need to sleep. If the desired tick time is more than the current tick time + 16 milliseconds, then we will sleep for (at least) 16 milliseconds and check it again on the next cycle.  &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;if (frameLimit &amp;gt; ticks + 16)&lt;br /&gt;{&lt;br /&gt;    SDL_Delay(16);&lt;br /&gt;}&lt;/pre&gt;Finally, if the difference in the tick times is between 1 and 16 then we will sleep for that difference. &lt;br /&gt;&lt;pre class="cpp" name="code"&gt;else&lt;br /&gt;{&lt;br /&gt;    SDL_Delay(frameLimit - ticks);&lt;br /&gt;}&lt;/pre&gt;This ensures that we limit the number of frames per second of the program and also return spare cycles back to the CPU.    &lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=313223966295810607" name="Conclusion"&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;As you can see, controlling basic movement is quite straight forward. In the next tutorial, we will look at firing a bullet and how to control reload times.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=313223966295810607" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial04.tar.gz/download"&gt;tutorial04.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-313223966295810607?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/313223966295810607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-4-controlling.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/313223966295810607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/313223966295810607'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-4-controlling.html' title='Basic Game Tutorial #4 - Controlling a sprite'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-BWdkJSqyCmI/ToDaMJW6GqI/AAAAAAAAAys/sOqzSJ_Js-U/s72-c/tutorial04.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-3908625741923822929</id><published>2011-09-27T12:04:00.000-07:00</published><updated>2011-09-27T12:04:24.226-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='sound'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Basic Game Tutorial #3 - Images and Sound</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #3 - Images and Sound&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-ddB0m4Lb-Rg/ToDaL5dd8MI/AAAAAAAAAyo/hi6WggLTSx4/s1600/tutorial02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="253" src="http://3.bp.blogspot.com/-ddB0m4Lb-Rg/ToDaL5dd8MI/AAAAAAAAAyo/hi6WggLTSx4/s320/tutorial02.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;An SDL window displaying an image and playing a sound&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;This third tutorial deals with playing sound in SDL.&lt;br /&gt;Compile and run tutorial03. By pressing Space, you can play a sound clip. Pressing Escape or closing the window will exit.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;Two new files are introduced &lt;span class="code"&gt;audio.c&lt;/span&gt; and &lt;span class="code"&gt;audio.h&lt;/span&gt;.&lt;br /&gt;The &lt;span class="code"&gt;defs.h&lt;/span&gt; file contains a new include, &lt;span class="code"&gt;SDL/SDL_mixer.h&lt;/span&gt;. SDL is limited to playing WAV files so SDL_mixer allows us to also play music and use other sound types such as OGG. Like SDL_image, it is a very useful addition.  &lt;span class="code"&gt;main.h&lt;/span&gt; introduces a new structure, &lt;span class="code"&gt;Mix_Chunk&lt;/span&gt;, which we will use to store the sound that we wish to play.&lt;br /&gt;&lt;span class="code"&gt;main.c&lt;/span&gt; contains an additional function call, &lt;span class="code"&gt;loadSound&lt;/span&gt; which is stored in &lt;span class="code"&gt;audio.c&lt;/span&gt;.&lt;br /&gt;In &lt;span class="code"&gt;init.c&lt;/span&gt; we initialise SDL's audio system in addition to its video system.&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)&lt;/pre&gt;Once again, if this call fails then we cannot continue, so we would simply exit the program. Once the system is up and running, we attempt open the audio:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 4096)&lt;/pre&gt;This call can fail for a valid reason, such as another process locking the audio or the system simply not having a sound card. Best practice would be to set a flag telling the program not to play any audio, but since this tutorial is reliant on it, we would exit if we couldn't play any sounds. The &lt;span class="code"&gt;Mix_OpenAudio&lt;/span&gt; function takes 4 arguments, the frequency of the audio, the format of the audio, the channels (1 for mono, 2 for stereo) and the chunksize of the audio. 22050 is fairly standard for most games, it can be as high as 44100, which is CD quality, but this uses up a lot of CPU time so we leave it at 22050. AUDIO_S16SYS is standard 16 bit sound, there are other formats but some of them are not portable to other systems. 2 simply tells the audio to be played in stereo rather than mono (1). 4096 is a reasonable chunksize, if the chunksize is too big then there will be a delay between when the sound is told to play and when it actually does play. Conversely, if the chunksize is too small then the sound will stutter because of the constant filling and emptying. &lt;br /&gt;Like &lt;span class="code"&gt;SDL_Surfaces&lt;/span&gt;s, &lt;span class="code"&gt;Mix_Chunk&lt;/span&gt;s must be freed when they are no longer needed. The function call&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;Mix_FreeChunk(dexterBark);&lt;/pre&gt;frees the chunk. The audio system must also be closed at the end of the program. So&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;Mix_CloseAudio();&lt;/pre&gt;is called before &lt;span class="code"&gt;SDL_Quit&lt;/span&gt;.  &lt;span class="code"&gt;input.c&lt;/span&gt; now calls the function &lt;span class="code"&gt;playSound&lt;/span&gt; when Space is pressed. The function is stored in &lt;span class="code"&gt;audio.c&lt;/span&gt;&lt;br /&gt;&lt;span class="code"&gt;graphics.c&lt;/span&gt; has not changed.&lt;br /&gt;&lt;span class="code"&gt;audio.c&lt;/span&gt; contains 2 function calls, &lt;span class="code"&gt;loadSound&lt;/span&gt; and &lt;span class="code"&gt;playSound&lt;/span&gt;. The &lt;span class="code"&gt;loadSound&lt;/span&gt; function loads the audio file&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;Mix_Chunk *sfx = Mix_LoadWAV(name);&lt;/pre&gt;As with &lt;span class="code"&gt;IMG_Load&lt;/span&gt;, there is no need to specify the file type as &lt;span class="code"&gt;SDL_mixer&lt;/span&gt; will check the extension of the file. &lt;span class="code"&gt;Mix_LoadWAV&lt;/span&gt; will return the loaded audio chunk or &lt;span class="code"&gt;NULL&lt;/span&gt; if it fails. &lt;br /&gt;&lt;span class="code"&gt;playSound&lt;/span&gt; will play the specified audio file by calling&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;Mix_PlayChannel(-1, sfx, 0);&lt;/pre&gt;The first argument is the channel to play the sound on. You may wish to do this if you wanted to have, say, a person speaking and you wanted to have them interupted. Specifying -1 tells SDL to play the sound on the first free channel that it finds. The second argument is the sound chunk to play and the third argument is the additional number of times to play the sound, so 0 means to play it 0 additional times and 1 means to play it 1 additional time etc. Specifying -1 will loop the sound forever.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3716484034095527645&amp;amp;postID=3908625741923822929" name="Conclusion"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Now that we have dealt with opening windows, displaying images and playing sounds, we can start looking at intermediate topics such as input control and collision detection.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial03.tar.gz/download"&gt;tutorial03.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-3908625741923822929?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/3908625741923822929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-3-images-and-sound.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/3908625741923822929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/3908625741923822929'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-3-images-and-sound.html' title='Basic Game Tutorial #3 - Images and Sound'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-ddB0m4Lb-Rg/ToDaL5dd8MI/AAAAAAAAAyo/hi6WggLTSx4/s72-c/tutorial02.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-4763401561819770632</id><published>2011-09-26T19:15:00.000-07:00</published><updated>2011-09-27T11:03:54.265-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='image'/><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Basic Game Tutorial #2 - Displaying an image</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #2 - Displaying an image&lt;/span&gt;&lt;/div&gt;&lt;div style="font-size: 24pt; text-align: center;"&gt;&lt;img border="0" height="253" src="http://3.bp.blogspot.com/-ddB0m4Lb-Rg/ToDaL5dd8MI/AAAAAAAAAyo/hi6WggLTSx4/s320/tutorial02.png" width="320" /&gt;&lt;span style="font-size: 14pt;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;An SDL window displaying an image&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;br /&gt;In this second tutorial, we will explain how to display an image in SDL. If you have not read the first tutorial, you are advised to do so as only new function calls will be explained.&lt;br /&gt;Compile and run the program as before. Note that the executable is called tutorial02. If successful you should see a window similar to the one in the screenshot. As before, you can exit the program by either closing the window or pressing Escape.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;In the src directory, you will see that there are 2 new files:  &lt;span class="code"&gt;graphics.c&lt;/span&gt; and &lt;span class="code"&gt;graphics.h&lt;/span&gt;. Other files have changed too though, so we will go through these as well.&lt;br /&gt;The &lt;span class="code"&gt;defs.h&lt;/span&gt; file contains a new include, &lt;span class="code"&gt;SDL/SDL_image.h&lt;/span&gt;. SDL is limited to only loading BMP files, so this include allows us to load other file types, such as JPEGs and PNGs, so it is very useful to have.  &lt;span class="code"&gt;main.h&lt;/span&gt; includes an additional &lt;span class="code"&gt;SDL_Surface&lt;/span&gt;, which we will use to store the image that we load.&lt;br /&gt;&lt;span class="code"&gt;main.c&lt;/span&gt; has changed slightly. We now have to additional function calls, &lt;span class="code"&gt;loadImage&lt;/span&gt; and &lt;span class="code"&gt;updateScreen&lt;/span&gt;. Both these functions are in &lt;span class="code"&gt;graphics.c&lt;/span&gt; which we will look at shortly.&lt;br /&gt;&lt;span class="code"&gt;init.h&lt;/span&gt; contains a reference to the external new &lt;span class="code"&gt;SDL_Surface&lt;/span&gt;.&lt;br /&gt;&lt;span class="code"&gt;init.c&lt;/span&gt; is slightly different. We initialise SDL as before, but we pass in an additional flag to the window creation&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;screen = SDL_SetVideoMode(640, 480, 0, SDL_HWPALETTE|SDL_DOUBLEBUF);&lt;/pre&gt;The &lt;span class="code"&gt;SDL_DOUBLEBUF&lt;/span&gt; flag tells SDL to use double buffering which prevents flickering when displaying moving images. Double buffering works by rendering the screen to be displayed to an offscreen image and then showing it when it is complete. The onscreen image is then swapped with the offscreen image and is then used for rendering the next screen. The swapping of the buffers is not automatic though and must be called manually. The &lt;span class="code"&gt;cleanup&lt;/span&gt; function now has an additional function call&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_FreeSurface(dexterImage);&lt;/pre&gt;All &lt;span class="code"&gt;SDL_Surface&lt;/span&gt;s must be freed after they have been used. The only exception to this rule is the surface used to create the SDL window. This surface is freed when &lt;span class="code"&gt;SDL_Quit&lt;/span&gt; is called.  &lt;span class="code"&gt;input.h&lt;/span&gt; and &lt;span class="code"&gt;input.c&lt;/span&gt; have not changed.&lt;br /&gt;&lt;span class="code"&gt;graphics.h&lt;/span&gt; contains the &lt;span class="code"&gt;defs.h&lt;/span&gt; include and the external declarations of our 2 surfaces. Since the header files only ever contain the includes and references to external variables, they will not be discussed anymore.&lt;br /&gt;&lt;span class="code"&gt;graphics.h&lt;/span&gt; contains the &lt;span class="code"&gt;defs.h&lt;/span&gt; include and the external declarations of our 2 surfaces. Since the header files only ever contain the includes and references to external variables, they will not be discussed anymore.&lt;br /&gt;&lt;span class="code"&gt;graphics.c&lt;/span&gt; contains 3 function calls, &lt;span class="code"&gt;loadImage&lt;/span&gt;, &lt;span class="code"&gt;drawImage&lt;/span&gt; and &lt;span class="code"&gt;updateScreen&lt;/span&gt;. The &lt;span class="code"&gt;loadImage&lt;/span&gt; function contains numerous SDL function calls:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_Surface *loadImage(char *name)&lt;br /&gt;{&lt;br /&gt;/* Load the image using SDL Image */&lt;br /&gt;&lt;br /&gt;SDL_Surface *temp = IMG_Load(name);&lt;br /&gt;SDL_Surface *image;&lt;br /&gt;&lt;br /&gt;if (temp == NULL)&lt;br /&gt;{&lt;br /&gt;printf("Failed to load image %s\n", name);&lt;br /&gt;&lt;br /&gt;return NULL;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Make the background transparent */&lt;br /&gt;&lt;br /&gt;SDL_SetColorKey(temp, (SDL_SRCCOLORKEY|SDL_RLEACCEL),&lt;br /&gt;SDL_MapRGB(temp-&amp;gt;format, 0, 0, 0));&lt;br /&gt;&lt;br /&gt;/* Convert the image to the screen's native format */&lt;br /&gt;&lt;br /&gt;image = SDL_DisplayFormat(temp);&lt;br /&gt;&lt;br /&gt;SDL_FreeSurface(temp);&lt;br /&gt;&lt;br /&gt;if (image == NULL)&lt;br /&gt;{&lt;br /&gt;printf("Failed to convert image %s to native format\n", name);&lt;br /&gt;&lt;br /&gt;return NULL;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Return the processed image */&lt;br /&gt;&lt;br /&gt;return image;&lt;br /&gt;}&lt;/pre&gt;The &lt;span class="code"&gt;IMG_Load&lt;/span&gt; function is from &lt;span class="code"&gt;SDL_image&lt;/span&gt; and allows us to load JPEGs and PNGs. There is no need to specify what the file type is as it will use the file's extension to figure out what it is. The function returns an &lt;span class="code"&gt;SDL_Surface&lt;/span&gt; if successful or &lt;span class="code"&gt;NULL&lt;/span&gt; if it fails. The next function call&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_SetColorKey(temp,(SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(temp-&amp;gt;format, 0, 0, 0));&lt;/pre&gt;makes one of the colours in the image transparent. This function takes 3 arguments. The first is the image to process, the second is a flag: &lt;span class="code"&gt;SDL_SRCCOLORKEY&lt;/span&gt; makes the 3rd argument the transparent pixel in the source image of the blit. &lt;span class="code"&gt;SDL_RLEACCEL&lt;/span&gt; improves blitting performance, which is desirable. The third argument is the color of the pixel to make transparent, we use &lt;span class="code"&gt;SDL_MapRGB&lt;/span&gt; for this&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_MapRGB(temp-&amp;gt;format, 0, 0, 0)&lt;/pre&gt;&lt;span class="code"&gt;SDL_MapRGB&lt;/span&gt; takes 4 arguments, the surface's pixel format and the RGB values of the colour desired. The function then returns the pixel value of the desired colour. Finally, we need to convert the loaded image to the current display's format. This is important because otherwise SDL will need to perform this conversion every time we attempt to blit the image to the screen, and this will consume a lot of CPU power and slow down our program. The function call &lt;span class="code"&gt;SDL_DisplayFormat&lt;/span&gt; takes care of this:&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;image = SDL_DisplayFormat(temp);&lt;/pre&gt;This function will return the converted image. It is important that we do not reassign the pointer to the unconverted surface to the newly converted surface as we need to free the old surface afterwards to avoid a memory leak. We free the old surface by calling&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_FreeSurface(temp);&lt;/pre&gt;After this, we need to check that the surface converted successfully. If it did not then we will note the error and return &lt;span class="code"&gt;NULL&lt;/span&gt;.    The second function, &lt;span class="code"&gt;drawImage&lt;/span&gt; is used to render an &lt;span class="code"&gt;SDL_Surface&lt;/span&gt; to the screen. We use an &lt;span class="code"&gt;SDL_Rect&lt;/span&gt; structure to do this. The &lt;span class="code"&gt;SDL_Rect&lt;/span&gt; contains 4 variables, x, y, w (width) and h (height). We set the width and height of the rectangle to the width and height of the surface to be rendered and the x and y to the values passed into the function. We then call&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_BlitSurface(image, NULL, screen, &amp;amp;dest);&lt;/pre&gt;The first argument is the image to be blitted, the second is the clipping rectangle. If we only wanted a portion of the image, we would have used another &lt;span class="code"&gt;SDL_Rect&lt;/span&gt; and set its x, y, w and h to the required values of the portion of the image we wanted. Since we want the entire image, we can pass in &lt;span class="code"&gt;NULL&lt;/span&gt; and SDL will assume we want the whole image. The third argument is the target surface, most usually the screen, but it could also be used to construct another image that would later be blitted to the screen. The fourth argument is the area of the target surface to render to, as specified by the values stored in the &lt;span class="code"&gt;SDL_Rect&lt;/span&gt;. &lt;br /&gt;The final function &lt;span class="code"&gt;updateScreen&lt;/span&gt;, is the master drawing function. The first function call&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_FillRect(screen, NULL, 0);&lt;/pre&gt;is used to blank the screen. &lt;span class="code"&gt;SDL_FillRect&lt;/span&gt; takes 3 arguments, the target surface, an &lt;span class="code"&gt;SDL_Rect&lt;/span&gt; containing the coordinates to fill and the colour of the fill (using &lt;span class="code"&gt;SDL_MapRGB&lt;/span&gt;). Passing in NULL for the second argument will make SDL assume that we want to fill the entire surface. 0 in the third argument is simply black. We then call &lt;span class="code"&gt;drawImage&lt;/span&gt; to draw the image at the specified coordinates. The final call in this function&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_Flip(screen);&lt;/pre&gt;swaps the image buffers on the screen. Since we created the window with the flag &lt;span class="code"&gt;SDL_DOUBLEBUF&lt;/span&gt;, this is required otherwise nothing will be displayed when the program is run.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Conclusion"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;Hopefully you should now have an understanding of how to display images in SDL. The next tutorial will look at playing sounds.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial02.tar.gz/download"&gt;tutorial02.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-4763401561819770632?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/4763401561819770632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-2-displaying-image.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4763401561819770632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4763401561819770632'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-2-displaying-image.html' title='Basic Game Tutorial #2 - Displaying an image'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-ddB0m4Lb-Rg/ToDaL5dd8MI/AAAAAAAAAyo/hi6WggLTSx4/s72-c/tutorial02.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-9025169303227959527</id><published>2011-09-26T19:10:00.000-07:00</published><updated>2011-09-27T11:03:42.850-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sdl'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><title type='text'>Basic Game Tutorial #1 - Opening a Window</title><content type='html'>&lt;div style="font-size: 24pt; text-align: center;"&gt;Basic Tutorials&lt;br /&gt;&lt;span style="font-size: 14pt;"&gt;Basic Game Tutorial #1 - Opening a Window&lt;/span&gt;&lt;/div&gt;&lt;table align="CENTER"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="CENTER"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-F7RbVTdMA1w/ToDaK2dJdLI/AAAAAAAAAyk/UlSxUauVg_s/s1600/tutorial01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="253" src="http://4.bp.blogspot.com/-F7RbVTdMA1w/ToDaK2dJdLI/AAAAAAAAAyk/UlSxUauVg_s/s320/tutorial01.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="color: #00aaff; font-size: 11px; text-align: center;"&gt;An SDL window&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Introduction"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Introduction&lt;/div&gt;&lt;div style="color: red;"&gt;&lt;br /&gt;Warning: These tutorials assume that you are already familiar with C programming and you are comfortable with advanced topics such as pointers, as well as using Makefiles. You are also advised to follow the tutorials in order, rather than just jumping around as prior knowledge is assumed throughout.&lt;/div&gt;&lt;br /&gt;This first tutorial will explain how to open a window in SDL. Before you can do anything however, you will need to make sure you have the relevant libraries for SDL installed. Linux users can download the required SDL files from their repository. These are the files that you need to compile and run the tutorials:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;libsdl1.2-dev&lt;/li&gt;&lt;li&gt;libsdl-image1.2-dev&lt;/li&gt;&lt;li&gt;libsdl-mixer1.2-dev&lt;/li&gt;&lt;li&gt;libsdl-ttf2.0-dev&lt;/li&gt;&lt;/ul&gt;Once you have installed the development files, you should attempt to compile the program. Open up a console window, navigate to the tutorial_01 directory and type&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;make&lt;/pre&gt;&lt;br /&gt;The program should compile successfully, but if you have not installed SDL correctly, you may receive an error message similar to this&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;In file included from src/init.h:1,&lt;br /&gt;from src/init.c:1:&lt;br /&gt;src/defs.h:4:22: error: SDL/SDL.h: No such file or directory&lt;/pre&gt;&lt;br /&gt;If this happens you should double check that SDL is in the compiler's  search path. Once you manage to compile the program, run it by typing&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;./tutorial01&lt;/pre&gt;&lt;br /&gt;This will open up the window. You can close the window by either pressing &lt;span class="code"&gt;ESCAPE&lt;/span&gt;  or closing the window using the mouse. Congratulations, you just compiled and ran your first SDL program!&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="An indepth look"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;An indepth look&lt;/div&gt;&lt;br /&gt;If you look in the src directory, you will see that there are 7 files:  &lt;span class="code"&gt;defs.h, init.c, init.h, main.c, main.h, input.c&lt;/span&gt; and  &lt;span class="code"&gt;input.h&lt;/span&gt; We'll look at each of these in turn.&lt;br /&gt;The &lt;span class="code"&gt;defs.h&lt;/span&gt; file contains all the includes required to compile the program. The only include that would probably won't have seen before is the &lt;span class="code"&gt;SDL/SDL.h&lt;/span&gt; include. This contains all the structures and functions required to compile an SDL program. More includes will be added in later tutorials.  &lt;span class="code"&gt;main.h&lt;/span&gt; includes the &lt;span class="code"&gt;defs.h&lt;/span&gt; and contains our first SDL structure, &lt;span class="code"&gt;SDL_Surface&lt;/span&gt;. This structure is essentially a bitmap, so it is used to display images on the screen. An &lt;span class="code"&gt;SDL_Surface&lt;/span&gt; is also required when opening an SDL window.&lt;br /&gt;&lt;span class="code"&gt;main.c&lt;/span&gt; is our main file, which contains the standard &lt;span class="code"&gt;main&lt;/span&gt; function. &lt;span class="code"&gt;main.h&lt;/span&gt; is included in this file. The first function we call is &lt;span class="code"&gt;init()&lt;/span&gt; which will setup our SDL environment for us. The &lt;span class="code"&gt;cleanup&lt;/span&gt; function we call &lt;span class="code"&gt;atexit&lt;/span&gt; frees any allocated memory and quits SDL. We then loop indefinitely and call the function &lt;span class="code"&gt;getInput()&lt;/span&gt; to process messages. Below this function call however, is an SDL function&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_Delay(16);&lt;/pre&gt;&lt;br /&gt;This function will sleep for a MINIMUM of 16 milliseconds before continuing. The reason why this is a minimum and not an exact amount is because of OS scheduling and how it decides to allocate CPU time to processes. Telling your program to sleep prevents it from sucking up all the CPU time. 16 milliseconds is roughly 60 frames per second, but depending on scheduling it might run slightly faster or slower. Now we will look at initialising SDL.  &lt;span class="code"&gt;init.h&lt;/span&gt; is mostly the same as &lt;span class="code"&gt;main.h&lt;/span&gt;, except that we reference the &lt;span class="code"&gt;SDL_Surface&lt;/span&gt; as an external variable.&lt;br /&gt;&lt;span class="code"&gt;init.c&lt;/span&gt; is where the most important function calls reside. We include &lt;span class="code"&gt;init.h&lt;/span&gt; and then initalise SDL by calling the function&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_Init(SDL_INIT_VIDEO)&lt;/pre&gt;&lt;br /&gt;This tells SDL to initialise the video system, so that we can display images. SDL has numerous systems which can be initialised by setting extra bits on the parameter. We'll be doing this in later tutorials. If this call had failed for any reason, the function will return -1. If this happens then we can't continue so we note the error and exit the program. Once SDL has intialised, we can then open our window:&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;screen = SDL_SetVideoMode(640, 480, 0, SDL_HWPALETTE);&lt;/pre&gt;&lt;br /&gt;The &lt;span class="code"&gt;SDL_SetVideoMode&lt;/span&gt; function takes 4 parameters, width, height, bits per pixel (bpp) and a set of flags. The width and height are self explanatory and we set the bpp to 0 to make SDL use the current BPP, which in most setups will be either 16, 24 or 32 bit. The &lt;span class="code"&gt;SDL_HWPALETTE&lt;/span&gt; flag tells SDL to use video memory for the window rather than software memory. Video memory is faster than software memory since it will use your dedicated graphics card. This forth parameter can have extra bits OR'd onto it, so we could have opened a fullscreen window instead, by using &lt;span class="code"&gt;SDL_FULLSCREEN&lt;/span&gt;, but for the moment we will open a window. This function call returns an &lt;span class="code"&gt;SDL_Surface&lt;/span&gt; which we reference using our &lt;span class="code"&gt;screen&lt;/span&gt; surface. If this surface is &lt;span class="code"&gt;NULL&lt;/span&gt; then we couldn't open our screen and can't continue, so we would note this error and exit the program. Finally, we set the screen title by calling&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_WM_SetCaption(title, NULL);&lt;/pre&gt;&lt;br /&gt;This simply sets the window's title to whatever text we want. The second argument is the window's title when it is minimised, but we won't worry about this. That's all we needed to do to initialise SDL. The &lt;span class="code"&gt;cleanup&lt;/span&gt; function calls one simple function&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_Quit();&lt;/pre&gt;&lt;br /&gt;which closes our window, shuts down SDL and exits our program. Since we assigned this function to &lt;span class="code"&gt;atexit()&lt;/span&gt;, this function will be called whenever the program is told to &lt;span class="code"&gt;exit()&lt;/span&gt;.  Our final pair of files deal with input handling. &lt;span class="code"&gt;input.h&lt;/span&gt; contains nothing apart from our &lt;span class="code"&gt;defs.h&lt;/span&gt; so we'll move onto &lt;span class="code"&gt;input.c&lt;/span&gt; which contains a single function. &lt;span class="code"&gt;SDL_Event&lt;/span&gt; is our event structure where we will store event information. We then call the function&lt;br /&gt;&lt;br /&gt;&lt;pre class="cpp" name="code"&gt;SDL_PollEvent()&lt;/pre&gt;&lt;br /&gt;We continuously call this function while there are still messages in the queue. Messages are things like key presses, mouse clicks, joystick movement, window minimisation, closing etc. When we get a message, it is stored in the &lt;span class="code"&gt;SDL_Event&lt;/span&gt; structure and we then process it by switching its &lt;span class="code"&gt;type&lt;/span&gt;. The &lt;span class="code"&gt;SDL_QUIT&lt;/span&gt; event type will appear when you attempt to close the window, so we catch this and exit the program cleanly. The second event type we check for is &lt;span class="code"&gt;SDL_KEYDOWN&lt;/span&gt;. This event occurs when a key is pressed down. When this happens we switch our event's &lt;span class="code"&gt;key.keysym.sym&lt;/span&gt; to tell us what keyboard symbol was pressed, where &lt;span class="code"&gt;key&lt;/span&gt; is the SDL_KeyboardEvent structure, &lt;span class="code"&gt;keysym&lt;/span&gt; is its &lt;span class="code"&gt;SDL_keysym&lt;/span&gt; structure and, finally, &lt;span class="code"&gt;sym&lt;/span&gt; the &lt;span class="code"&gt;SDLKey&lt;/span&gt; that was pressed. The only key we're interested in reading at the moment is Escape, which is noted in SDL by &lt;span class="code"&gt;SDLK_ESCAPE&lt;/span&gt;. We will exit the program if this key is pressed too.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Conclusion"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Conclusion&lt;/div&gt;&lt;br /&gt;So you now know how to open an SDL window, wait for input and exit as appropriate. In the next tutorial we will look at displaying an image on the screen.&lt;br /&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=3716484034095527645" name="Downloads"&gt;&lt;/a&gt; &lt;br /&gt;&lt;div style="background-color: #000035; border: 1px solid rgb(0, 0, 119); font-size: 14pt; font-weight: bold;"&gt;&amp;nbsp;Downloads&lt;/div&gt;&lt;br /&gt;Source Code - &lt;a href="http://sourceforge.net/projects/sdltutorials/files/tutorial01.tar.gz/download"&gt;tutorial01.tar.gz&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-9025169303227959527?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/9025169303227959527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-1-opening-window.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/9025169303227959527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/9025169303227959527'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/basic-game-tutorial-1-opening-window.html' title='Basic Game Tutorial #1 - Opening a Window'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-F7RbVTdMA1w/ToDaK2dJdLI/AAAAAAAAAyk/UlSxUauVg_s/s72-c/tutorial01.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-302007173026607115</id><published>2011-09-25T01:09:00.000-07:00</published><updated>2011-09-25T09:10:54.816-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Using the AlarmManager for updating Android Widgets</title><content type='html'>I see people asking repeatedly about how to update an Android widget more often than the restricted 30 minute interval that is enforced by the OS. Before we begin, I just want to point out and make one thing very clear: unless you have absolute reason to do so, you shouldn't be asking your widget to update more frequently than this. There probably isn't need to, to be honest. Once an hour will suffice for most people, such as if it's a weather app or checking feeds or something else that can't be made to receive broadcast or push notifications. The two main reasons behind this are as follows:&lt;br /&gt;&lt;br /&gt;1. It will reduce the battery life of the phone.&lt;br /&gt;&lt;br /&gt;2. Handled badly and your widget could end up making the phone completely unresponsive. Pushing updates to onscreen widgets is a somewhat costly process.&lt;br /&gt;&lt;br /&gt;Now that you've read and understood the implications, let's move onto how to use an AlarmManager. Normally, when setting up an AppWidget, you will supply the update interval in milliseconds (as updateTimeMillis). There are two disadvantages to this. The first, as pointed out, is the minimum of 30 minutes (you'll see no warning about this if you lower it, by the way). The second, less obvious one, is that the time isn't predictable. That is to say, if you wanted to widget to always update once an hour, on the hour, it's near-impossible. Likewise, if you wanted to widget to update at 0, 15, 30 and 45 minutes past each hour, you can't do that, either.&lt;br /&gt;&lt;br /&gt;Here's how we're going to solve this problem (note: this tutorial assumes that you already have knowledge of app widgets and services).&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public class MyWidget extends AppWidgetProvider&lt;br /&gt;{&lt;br /&gt;    private PendingIntent service = null;&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)&lt;br /&gt;    {&lt;br /&gt;        final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);&lt;br /&gt;&lt;br /&gt;        final Calendar TIME = Calendar.getInstance();&lt;br /&gt;        TIME.set(Calendar.MINUTE, 0);&lt;br /&gt;        TIME.set(Calendar.SECOND, 0);&lt;br /&gt;        TIME.set(Calendar.MILLISECOND, 0);&lt;br /&gt;&lt;br /&gt;        final Intent i = new Intent(context, MyService.class);&lt;br /&gt;&lt;br /&gt;        if (service == null)&lt;br /&gt;        {&lt;br /&gt;            service = PendingIntent.getService(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        m.setRepeating(AlarmManager.RTC, TIME.getTime().getTime(), 1000 * 60, service);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public void onDisabled(Context context)&lt;br /&gt;    {&lt;br /&gt;        final AlarmManager m = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);&lt;br /&gt;&lt;br /&gt;        m.cancel(service);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/PRE&gt;and a cut down service example. The service is where we perform our logic and update the AppWidget.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;public class MyService extends Service&lt;br /&gt;{&lt;br /&gt;    @Override&lt;br /&gt;    public void onCreate()&lt;br /&gt;    {&lt;br /&gt;        super.onCreate();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public int onStartCommand(Intent intent, int flags, int startId)&lt;br /&gt;    {&lt;br /&gt;        buildUpdate();&lt;br /&gt;&lt;br /&gt;        return super.onStartCommand(intent, flags, startId);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void buildUpdate()&lt;br /&gt;    {&lt;br /&gt;        String lastUpdated = DateFormat.format("MMMM dd, yyyy h:mmaa", new Date()).toString();&lt;br /&gt;&lt;br /&gt;        RemoteViews view = new RemoteViews(getPackageName(), R.layout.widget);&lt;br /&gt;&lt;br /&gt;        view.setTextViewText(R.id.lastUpdated, lastUpdated);&lt;br /&gt;&lt;br /&gt;        // Push update for this widget to the home screen&lt;br /&gt;        ComponentName thisWidget = new ComponentName(this, MyWidget.class);&lt;br /&gt;        AppWidgetManager manager = AppWidgetManager.getInstance(this);&lt;br /&gt;        manager.updateAppWidget(thisWidget, view);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public IBinder onBind(Intent intent)&lt;br /&gt;    {&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/PRE&gt;(note: you should think carefully before making your service START_STICKY, as this means the service should be explicitly stopped. Since we're running a one off procedure, we want to have this hanging around as little as possible. Don't be tempted to use a BroadcastReceiver here, as these are designed for very fast operations. Anything taking more than about 10 seconds will be seen as misbehaving by the Android OS and might be killed off)&lt;br /&gt;&lt;br /&gt;Our Alarm is set up in the widget's onUpdate method. It shouldn't look that much different to how a standard AppWidget call to a service looks, except for that we're scheduling the alarm to do the work. Note that we're telling the widget to repeat the call once a minute. This is fine for our example, since you don't want to sit around for 15 minutes to see the results. However, in real life you will want it to do so less frequently.&lt;br /&gt;&lt;br /&gt;We're also telling the alarm to kick off immediately. If we want it to kick off at an exact time, we'll need to create it. The simplest way is with the calendar:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;Calendar TIME = Calendar.getInstance();&lt;br /&gt;TIME.set(Calendar.MINUTE, 0);&lt;br /&gt;TIME.set(Calendar.SECOND, 0);&lt;br /&gt;TIME.set(Calendar.MILLISECOND, 0);&lt;br /&gt;&lt;br /&gt;m.setRepeating(AlarmManager.RTC, TIME.getTime().getTime(), AlarmManager.INTERVAL_HOUR, service);&lt;br /&gt;&lt;/PRE&gt;The above will kick off the service once an hour, on the hour. You'll notice that the widget is updated immediately, which is normal. It does this because it "missed" it's previous alarm of the last hour. It'll then sit quietly until the next update is due.&lt;br /&gt;&lt;br /&gt;If you want the alarm to issue more frequently then you'll need to adjust the intervalPeriod.&lt;br /&gt;&lt;br /&gt;Finally, we come to an important step: how to stop the alarm! You'll notice that in our class we have declared:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;private PendingIntent service = null;&lt;br /&gt;&lt;/PRE&gt;which is set up later in the onUpdate (if it's not null). We need to keep hold of this so that we can cancel the alarm later! We do so in the onDisable() method which will be triggered when all widgets are removed from the screen. We pass the PendingIntent to the cancel method of the AlarmManager so that it can determine which alarm it must cancel.&lt;br /&gt;&lt;br /&gt;And there you have it. Pretty straight forward, really. If you have already created an AppWidget that calls a service, then you'll find you need only add in a handful of lines of code to have to AppWidget update more frequently, or at a more predictable interval.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-302007173026607115?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/302007173026607115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/using-alarmmanager-for-updating-android.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/302007173026607115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/302007173026607115'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/using-alarmmanager-for-updating-android.html' title='Using the AlarmManager for updating Android Widgets'/><author><name>Stephen J Sweeney</name><uri>http://www.blogger.com/profile/15661317377141414536</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_pUELf1ljwjs/SnHB4ItWPFI/AAAAAAAAAgo/blYnrw0gbPc/s1600-R/2813_1142226948789_1020926607_424894_2524651_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3716484034095527645.post-4073231471215032313</id><published>2011-09-23T04:05:00.000-07:00</published><updated>2011-09-23T04:05:42.434-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='blob and conquer'/><category scheme='http://www.blogger.com/atom/ns#' term='parallel realities'/><category scheme='http://www.blogger.com/atom/ns#' term='starfighter'/><category scheme='http://www.blogger.com/atom/ns#' term='blob wars'/><category scheme='http://www.blogger.com/atom/ns#' term='edgar'/><title type='text'>New Home</title><content type='html'>Since the hosting of the Parallel Realities website has now ended, we have opted to move the site to Blogger and make the binaries available for download on SourceForge.&lt;br /&gt;&lt;br /&gt;We'll add the tutorials and other bits and pieces over the next few weeks. In the meantime, you can download the latest version of The Legend of Edgar from the links below.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/legendofedgar/files/0.92/edgar-0.92-1.installer.exe/download"&gt;0.92 for Windows (32 bit)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/legendofedgar/files/0.92/edgar-0.92-1.i686.deb/download"&gt;0.92 for Linux (deb, 32 bit)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/legendofedgar/files/0.92/edgar-0.92-1.i686.rpm/download"&gt;0.92 for Linux (rpm, 32 bit)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/legendofedgar/files/0.92/edgar-0.92-1.x86_64.deb/download"&gt;0.92 for Linux (deb, 64 bit)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/legendofedgar/files/0.92/edgar-0.92-1.x86_64.rpm/download"&gt;0.92 for Linux (rpm, 64 bit)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/legendofedgar/files/0.92/edgar-0.92-1.tar.gz/download"&gt;0.92 source code&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sourceforge.net/apps/phpbb/legendofedgar/"&gt;Discussion Forum&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-FFwEKvxkaBc/TnYnP3b0frI/AAAAAAAAAxY/NW4OoQg1Txc/s1600/edgar39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-FFwEKvxkaBc/TnYnP3b0frI/AAAAAAAAAxY/NW4OoQg1Txc/s320/edgar39.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3716484034095527645-4073231471215032313?l=www.parallelrealities.co.uk' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.parallelrealities.co.uk/feeds/4073231471215032313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/new-home.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4073231471215032313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3716484034095527645/posts/default/4073231471215032313'/><link rel='alternate' type='text/html' href='http://www.parallelrealities.co.uk/2011/09/new-home.html' title='New Home'/><author><name>Richard Sweeney</name><uri>http://www.blogger.com/profile/11380481235671070530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-FFwEKvxkaBc/TnYnP3b0frI/AAAAAAAAAxY/NW4OoQg1Txc/s72-c/edgar39.png' height='72' width='72'/><thr:total>2</thr:total></entry></feed>
