logo
Free, unlimited AI code reviews that run on commit
git-lrc git-lrc GitHub Install Now We'd appreciate a star git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt

SDL::Tutorial::LunarLander - a small tutorial on Perl SDL

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.

       CREATINGADEMO

       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.

   FIRSTVERSION
       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???"

   CONTROLLINGTHESHIP
       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...

   HOWABOUTTHEGRAPHICS?
       Okay, okay... now that we have a working prototype, we can work on the graphics. But, first of all, we'll
       need...

       THEGRAPHICS

       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": (""images/background.jpg"" and ""images/ship.png"").

   USINGSDL
       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 "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 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.

Name

       SDL::Tutorial::LunarLander - a small tutorial on Perl SDL

   CATEGORY
       Tutorials

See Also