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