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