latest blog
[sdlgit/SDL-Site.git] / pages / SDL-Tutorial-LunarLander.html-inc
1 <div class="pod">
2 <!-- INDEX START -->
3 <h3 id="TOP">Index</h3>
4
5 <ul><li><a href="#NAME">NAME</a></li>
6 <li><a href="#INTRODUCTION">INTRODUCTION</a>
7 <ul>
8 <li>
9 <ul><li><a href="#CREATING_A_DEMO">CREATING A DEMO</a></li>
10 </ul>
11 </li>
12 <li><a href="#FIRST_VERSION">FIRST VERSION</a></li>
13 <li><a href="#CONTROLLING_THE_SHIP">CONTROLLING THE SHIP</a></li>
14 <li><a href="#HOW_ABOUT_THE_GRAPHICS">HOW ABOUT THE GRAPHICS?</a>
15 <ul><li><a href="#THE_GRAPHICS">THE GRAPHICS</a></li>
16 </ul>
17 </li>
18 <li><a href="#USING_SDL">USING SDL</a></li>
19 </ul>
20 </li>
21 <li><a href="#COPYRIGHT_amp_LICENSE">COPYRIGHT &amp; LICENSE</a>
22 </li>
23 </ul><hr />
24 <!-- INDEX END -->
25
26 <h1 id="NAME">NAME</h1><p><a href="#TOP" class="toplink">Top</a></p>
27 <div id="NAME_CONTENT">
28 <p>Lunar Lander - a small tutorial on Perl SDL</p>
29
30 </div>
31 <h1 id="INTRODUCTION">INTRODUCTION</h1><p><a href="#TOP" class="toplink">Top</a></p>
32 <div id="INTRODUCTION_CONTENT">
33 <p>This is a quick introduction to Games, Perl, and  SDL (Simple 
34 DirectMedia Layer, a cross-platform multimedia programming 
35 library). We'll write a small game -- Lunar Lander -- in 100 
36 lines of code, or less.</p>
37
38 </div>
39 <h3 id="CREATING_A_DEMO">CREATING A DEMO</h3>
40 <div id="CREATING_A_DEMO_CONTENT">
41 <p>You can see the final version of the demo code by doing:</p>
42 <p>&nbsp;</p>
43 <pre>   perl -MSDL::Tutorial::LunarLander=lander.pl -e1
44
45 </pre>
46 <p>&nbsp;</p>
47 <p>this will create all three files used in the tutorial:</p>
48
49
50
51
52
53 </div>
54 <h2 id="FIRST_VERSION">FIRST VERSION</h2>
55 <div id="FIRST_VERSION_CONTENT">
56 <p>We'll start with a text version of the game.</p>
57 <p>&quot;What?&quot;, you may ask. &quot;I thought it was a SDL tutorial&quot;.</p>
58 <p>Yes, it is -- thank you for reminding me. But we'll leave the SDL part for
59 later. We must build the game logic first!</p>
60 <p>One of the traps of game programming is focusing too much on the interface.
61 If we start with a simpler simulation, we can worry with the presentation
62 later.</p>
63 <p>So, here's the initial code:</p>
64 <p>&nbsp;</p>
65 <pre>    #!/usr/bin/perl
66
67     use strict;
68     use warnings;
69
70     my $height   = 1000; # m
71     my $velocity = 0;    # m/s
72     my $gravity  = 1;    # m/s^2
73
74     my $t = 0;
75
76     while ( $height &gt; 0 ) {
77         print &quot;at $t s height = $height m, velocity = $velocity m/s\n&quot;;
78
79         $height   = $height - $velocity;
80         $velocity = $velocity + $gravity;
81         $t        = $t + 1;
82     }
83
84     if ( $velocity &gt; 10 ) {
85         print &quot;CRASH!!!\n&quot;;
86     } else {
87         print &quot;You landed on the surface safely! :-D\n&quot;;
88     }
89
90 </pre>
91 <p>&nbsp;</p>
92 <p>Run the code and you'll see something like this:</p>
93 <p>&nbsp;</p>
94 <pre>    at 0 s height = 1000 m, velocity = 0 m/s
95     at 1 s height = 1000 m, velocity = 1 m/s
96     at 2 s height = 999 m, velocity = 2 m/s
97     at 3 s height = 997 m, velocity = 3 m/s
98     at 4 s height = 994 m, velocity = 4 m/s
99     at 5 s height = 990 m, velocity = 5 m/s
100     ...
101     at 43 s height = 97 m, velocity = 43 m/s
102     at 44 s height = 54 m, velocity = 44 m/s
103     at 45 s height = 10 m, velocity = 45 m/s
104
105     CRASH!!!
106
107 </pre>
108 <p>&nbsp;</p>
109 <p>&quot;What happened? How do I control the ship???&quot;</p>
110
111 </div>
112 <h2 id="CONTROLLING_THE_SHIP">CONTROLLING THE SHIP</h2>
113 <div id="CONTROLLING_THE_SHIP_CONTENT">
114 <p>The problem with our first spaceship is that it had no controls!</p>
115 <p>So, let's fix this problem, making the spaceship scriptable. (We 
116 could write some code to handle keyboard and joysticks now, but 
117 an scriptable spaceship will be easier to start. Remember, focus
118 on the game logic!)</p>
119 <p>So, create add this simple script to the end of your file:</p>
120 <p>&nbsp;</p>
121 <pre>    __DATA__
122     at 41s, accelerate 10 m/s^2 up
123     at 43s, 10 m/s^2
124     at 45s, 10
125     at 47s, 10
126     at 49s, 10
127
128 </pre>
129 <p>&nbsp;</p>
130 <p>The script is straightforward: it simply states a time when we
131 will push the spaceship up with a given acceleration. It accepts
132 free text: any two numbers you type will work.</p>
133 <p>We can parse the script using this regular expression:</p>
134 <p>&nbsp;</p>
135 <pre>    my $script_re = qr/(\d+) \D+ (\d+)/x;
136
137 </pre>
138 <p>&nbsp;</p>
139 <p>And we can build a hash of ( time =&gt; acceleration ) with:</p>
140 <p>&nbsp;</p>
141 <pre>    my %up = map { $_ =~ $script_re } &lt;DATA&gt;;
142
143 </pre>
144 <p>&nbsp;</p>
145 <p>So the middle section of the program will become:</p>
146 <p>&nbsp;</p>
147 <pre>    my $script_re = qr/(\d+) \D+ (\d+)/x;
148     my %up = map { $_ =~ $script_re } &lt;DATA&gt;;
149
150     while ( $height &gt; 0 ) {
151         print &quot;at $t s height = $height m, velocity = $velocity m/s\n&quot;;
152
153         if ( $up{$t} ) {
154             my $a = $up{$t};
155             print &quot;(accellerating $a m/s^2)\n&quot;;
156             $velocity = $velocity - $a;
157         }
158
159         $height   = $height - $velocity;
160         $velocity = $velocity + $gravity;
161         $t        = $t + 1;
162     }
163
164 </pre>
165 <p>&nbsp;</p>
166 <p>That's it!</p>
167 <p>Try to run the program, and the ship should land safely:</p>
168 <p>&nbsp;</p>
169 <pre>    ./lunar.pl autopilot.txt 
170     at 0 s height = 1000 m, velocity = 0 m/s
171     at 1 s height = 1000 m, velocity = 1 m/s
172     at 2 s height = 999 m, velocity = 2 m/s
173     at 3 s height = 997 m, velocity = 3 m/s
174     at 4 s height = 994 m, velocity = 4 m/s
175     at 5 s height = 990 m, velocity = 5 m/s
176     ...
177     at 54 s height = 19 m, velocity = 4 m/s
178     at 55 s height = 15 m, velocity = 5 m/s
179     at 56 s height = 10 m, velocity = 6 m/s
180     at 57 s height = 4 m, velocity = 7 m/s
181
182     You landed on the surface safely! :-D
183
184 </pre>
185 <p>&nbsp;</p>
186 <p>Cool, but...</p>
187
188 </div>
189 <h2 id="HOW_ABOUT_THE_GRAPHICS">HOW ABOUT THE GRAPHICS?</h2>
190 <div id="HOW_ABOUT_THE_GRAPHICS_CONTENT">
191 <p>Okay, okay... now that we have a working prototype, we can work on
192 the graphics. But, first of all, we'll need...</p>
193
194 </div>
195 <h3 id="THE_GRAPHICS">THE GRAPHICS</h3>
196 <div id="THE_GRAPHICS_CONTENT">
197 <p>Yes, the graphics.</p>
198 <p>We won't use anything fancy here, just two images: a large one, for
199 the background, and a smaller one for the spaceship.</p>
200 <p>Create the images using the Gimp, or use the images provided by
201 this tutorial; Save these images in a subdirectory called &quot;images&quot;:
202 (&quot;<code>images/background.jpg</code>&quot; and &quot;<code>images/ship.png</code>&quot;).</p>
203
204 </div>
205 <h2 id="USING_SDL">USING SDL</h2>
206 <div id="USING_SDL_CONTENT">
207 <p>First step: use the required libraries:</p>
208 <p>&nbsp;</p>
209 <pre>    use SDL; #needed to get all constants
210     use SDL::App;
211     use SDL::Surface;
212     use SDL::Rect;
213
214 </pre>
215 <p>&nbsp;</p>
216 <p>Second step: initialize <code>SDL::App</code>:</p>
217 <p>&nbsp;</p>
218 <pre>    my $app = SDL::App-&gt;new(
219         -title  =&gt; &quot;Lunar Lander&quot;,
220         -width  =&gt; 800,
221         -height =&gt; 600,
222         -depth  =&gt; 32,
223     );
224
225 </pre>
226 <p>&nbsp;</p>
227 <p>Third step: load the images and create the necessary &quot;rectangles&quot;:</p>
228 <p>&nbsp;</p>
229 <pre>    my $background = SDL::Surface-&gt;new( -name =&gt; 'images/background.jpg', );
230     my $ship       = SDL::Surface-&gt;new( -name =&gt; 'images/ship.png', );
231
232     my $background_rect = SDL::Rect-&gt;new(
233         -height =&gt; $background-&gt;height(),
234         -width  =&gt; $background-&gt;width(),
235     );
236
237     my $ship_rect = SDL::Rect-&gt;new(
238         -height =&gt; $ship-&gt;height(),
239         -width  =&gt; $ship-&gt;width(),
240     );
241
242 </pre>
243 <p>&nbsp;</p>
244 <p>Fourth step: create a sub to draw the spaceship and background:</p>
245 <p>&nbsp;</p>
246 <pre>    sub draw {
247         my ( $x, $y ) = @_; # spaceship position
248
249         # fix $y for screen resolution
250         $y = 450 * ( 1000 - $y ) / 1000;
251
252         # background
253         $background-&gt;blit( $background_rect, $app, $background_rect );
254
255         # ship
256         my $ship_dest_rect = SDL::Rect-&gt;new(
257             -height =&gt; $ship-&gt;height(),
258             -width  =&gt; $ship-&gt;width(),
259             -x      =&gt; $x,
260             -y      =&gt; $y,
261         );
262
263         $ship-&gt;blit( $ship_rect, $app, $ship_dest_rect );
264
265         $app-&gt;update($background_rect);
266     }
267
268 </pre>
269 <p>&nbsp;</p>
270 <p>Note that this sub first combines all the bitmaps, using a blit
271 (&quot;Block Image Transfer&quot;) operation -- which is quite fast, but does
272 not update the display.</p>
273 <p>The combined image is displayed in the last line. This process of
274 combining first, and displaying later, avoids that annoying fading
275 between cycles (&quot;flickering&quot;).</p>
276 <p>Finally, add the following lines to the end of the main loop, so that
277 we call the <code>draw()</code> function with the correct spaceship
278 coordinates:</p>
279 <p>&nbsp;</p>
280 <pre>    while ( $height &gt; 0 ) {
281
282         # ...
283
284         draw( 100, $height );
285         $app-&gt;delay(10);
286     }
287
288 </pre>
289 <p>&nbsp;</p>
290 <p>That's it!</p>
291 <p>Run the program and watch the spaceship landing safely on the surface
292 of the moon.</p>
293
294 </div>
295 <h1 id="COPYRIGHT_amp_LICENSE">COPYRIGHT &amp; LICENSE</h1><p><a href="#TOP" class="toplink">Top</a></p>
296 <div id="COPYRIGHT_amp_LICENSE_CONTENT">
297 <p>Copyright 2009 Nelson Ferraz, all rights reserved.</p>
298 <p>This program is free software; you can redistribute it and/or modify it
299 under the same terms as Perl itself.</p>
300
301 </div>
302 </div>