Commit | Line | Data |
b3ef54ec |
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 & 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> </p> |
43 | <pre> perl -MSDL::Tutorial::LunarLander=lander.pl -e1 |
44 | |
45 | </pre> |
46 | <p> </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>"What?", you may ask. "I thought it was a SDL tutorial".</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> </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 > 0 ) { |
77 | print "at $t s height = $height m, velocity = $velocity m/s\n"; |
78 | |
79 | $height = $height - $velocity; |
80 | $velocity = $velocity + $gravity; |
81 | $t = $t + 1; |
82 | } |
83 | |
84 | if ( $velocity > 10 ) { |
85 | print "CRASH!!!\n"; |
86 | } else { |
87 | print "You landed on the surface safely! :-D\n"; |
88 | } |
89 | |
90 | </pre> |
91 | <p> </p> |
92 | <p>Run the code and you'll see something like this:</p> |
93 | <p> </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> </p> |
109 | <p>"What happened? How do I control the ship???"</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> </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> </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> </p> |
135 | <pre> my $script_re = qr/(\d+) \D+ (\d+)/x; |
136 | |
137 | </pre> |
138 | <p> </p> |
139 | <p>And we can build a hash of ( time => acceleration ) with:</p> |
140 | <p> </p> |
141 | <pre> my %up = map { $_ =~ $script_re } <DATA>; |
142 | |
143 | </pre> |
144 | <p> </p> |
145 | <p>So the middle section of the program will become:</p> |
146 | <p> </p> |
147 | <pre> my $script_re = qr/(\d+) \D+ (\d+)/x; |
148 | my %up = map { $_ =~ $script_re } <DATA>; |
149 | |
150 | while ( $height > 0 ) { |
151 | print "at $t s height = $height m, velocity = $velocity m/s\n"; |
152 | |
153 | if ( $up{$t} ) { |
154 | my $a = $up{$t}; |
155 | print "(accellerating $a m/s^2)\n"; |
156 | $velocity = $velocity - $a; |
157 | } |
158 | |
159 | $height = $height - $velocity; |
160 | $velocity = $velocity + $gravity; |
161 | $t = $t + 1; |
162 | } |
163 | |
164 | </pre> |
165 | <p> </p> |
166 | <p>That's it!</p> |
167 | <p>Try to run the program, and the ship should land safely:</p> |
168 | <p> </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> </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 "images": |
202 | ("<code>images/background.jpg</code>" and "<code>images/ship.png</code>").</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> </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> </p> |
216 | <p>Second step: initialize <code>SDL::App</code>:</p> |
217 | <p> </p> |
218 | <pre> my $app = SDL::App->new( |
219 | -title => "Lunar Lander", |
220 | -width => 800, |
221 | -height => 600, |
222 | -depth => 32, |
223 | ); |
224 | |
225 | </pre> |
226 | <p> </p> |
227 | <p>Third step: load the images and create the necessary "rectangles":</p> |
228 | <p> </p> |
229 | <pre> my $background = SDL::Surface->new( -name => 'images/background.jpg', ); |
230 | my $ship = SDL::Surface->new( -name => 'images/ship.png', ); |
231 | |
232 | my $background_rect = SDL::Rect->new( |
233 | -height => $background->height(), |
234 | -width => $background->width(), |
235 | ); |
236 | |
237 | my $ship_rect = SDL::Rect->new( |
238 | -height => $ship->height(), |
239 | -width => $ship->width(), |
240 | ); |
241 | |
242 | </pre> |
243 | <p> </p> |
244 | <p>Fourth step: create a sub to draw the spaceship and background:</p> |
245 | <p> </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->blit( $background_rect, $app, $background_rect ); |
254 | |
255 | # ship |
256 | my $ship_dest_rect = SDL::Rect->new( |
257 | -height => $ship->height(), |
258 | -width => $ship->width(), |
259 | -x => $x, |
260 | -y => $y, |
261 | ); |
262 | |
263 | $ship->blit( $ship_rect, $app, $ship_dest_rect ); |
264 | |
265 | $app->update($background_rect); |
266 | } |
267 | |
268 | </pre> |
269 | <p> </p> |
270 | <p>Note that this sub first combines all the bitmaps, using a blit |
271 | ("Block Image Transfer") 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 ("flickering").</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> </p> |
280 | <pre> while ( $height > 0 ) { |
281 | |
282 | # ... |
283 | |
284 | draw( 100, $height ); |
285 | $app->delay(10); |
286 | } |
287 | |
288 | </pre> |
289 | <p> </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 & 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> |