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