fixed blit with new rect
[sdlgit/SDL_perl.git] / lib / SDL / Tutorial / LunarLander.pm
CommitLineData
9000d229 1=head1 NAME
2
3Lunar Lander - a small tutorial on Perl SDL
4
5=head1 INTRODUCTION
6
7This is a quick introduction to Perl and SDL (Simple DirectMedia
8Layer, a cross-platform multimedia programming library). We'll write
9a small game-- Lunar Lander-- in 100 lines of code, or less.
10
11=head2 PREPARATION
12
13You'll need SDL_Perl.
14
15If you are using Debian or Ubuntu, it's probably easier to install
16the module via apt-get:
17
18 apt-get install libsdl-perl
19
20or for the bleeding edge with tons of bug fixes.
21
22 perl -MCPAN -e "install SDL"
23
24If you are using other Linux distro, look for the corresponding
25package. If you can't find it you'll have to compile it (and deal
26with all the dependencies) yourself.
27
28The point is that it is strongly recommend that you start with a
29packaged module from your distribution. Avoid compiling SDL_Perl
30if you can.
31
32=head2 FIRST VERSION
33
34We'll start with a text version of the game.
35
36"What?", you may ask. "I thought it was a SDL tutorial".
37
38Yes, it is -- thank you for reminding me. But we'll leave the SDL part for
39later. We must build the game logic first!
40
41One of the traps of game programming is focusing too much on the interface.
42If we start with a simpler simulation, we can worry with the presentation
43later.
44
45So, 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
72Run 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
91The problem with our first spaceship is that it had no controls!
92
93So, let's fix this problem, making the spaceship scriptable. (We
94could write some code to handle keyboard and joysticks now, but
95an scriptable spaceship will be easier to start. Remember, focus
96on the game logic!)
97
98So, 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
107The script is straightforward: it simply states a time when we
108will push the spaceship up with a given acceleration. It accepts
109free text: any two numbers you type will work.
110
111We can parse the script using this regular expression:
112
113 my $script_re = qr/(\d+) \D+ (\d+)/x;
114
115And we can build a hash of ( time => acceleration ) with:
116
117 my %up = map { $_ =~ $script_re } <DATA>;
118
119So 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
138That's it!
139
140Try 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
157Cool, but...
158
159=head2 HOW ABOUT THE GRAPHICS?
160
161Okay, okay... now that we have a working prototype, we can work on
162the graphics. But, first of all, we'll need...
163
164=head3 THE GRAPHICS
165
166Yes, the graphics.
167
168We won't use anything fancy here, just two images: a large one, for
169the background, and a smaller one for the spaceship.
170
171Create the images using the Gimp, or use the images provided by
172this 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
177First 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
184Second 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
193Third 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
208Fourth 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
232Note that this sub first combines all the bitmaps, using a blit
233("Block Image Transfer") operation -- which is quite fast, but does
234not update the display.
235
236The combined image is displayed in the last line. This process of
237combining first, and displaying later, avoids that annoying fading
238between cycles ("flickering").
239
240Finally, add the following lines to the end of the main loop, so that
241we call the C<draw()> function with the correct spaceship
242coordinates:
243
244 while ( $height > 0 ) {
245
246 # ...
247
248 draw( 100, $height );
249 $app->delay(10);
250 }
251
252That's it!
253
254Run the program and watch the spaceship landing safely on the surface
255of the moon.
256
257=head1 COPYRIGHT & LICENSE
258
259Copyright 2009 Nelson Ferraz, all rights reserved.
260
261This program is free software; you can redistribute it and/or modify it
262under the same terms as Perl itself.
263