pods::...Lander(3pm)

✨ NAME ✨

SDL::Tutorial::LunarLander β€” a small tutorial on Perl SDL πŸš€πŸŒ™

(this page lives in the pods::...Lander(3pm) manual, bestie, so you're in the right place πŸ’…)

πŸŽ€ CATEGORY πŸŽ€

Tutorials


πŸ’– INTRODUCTION πŸ’–

Okay so this is a quick little intro to Games, Perl, and SDL β€” that's Simple DirectMedia Layer, a cross-platform multimedia programming library, iykyk. We're gonna write a small game β€” Lunar Lander β€” in 100 lines of code, or less. No cap. 🫢

🧚 CREATING A DEMO 🧚

You can peek at the final version of the demo code by running this, like, literally right now:

perl -MSDL::Tutorial::LunarLander=lander.pl -e1

and it will create all three files used in the tutorial. slay ✨

🌸 FIRST VERSION 🌸

We'll start with a text version of the game. πŸ’€

"What?", you may ask. "I thought it was a SDL tutorial".

Yes bestie, it is β€” thank you for reminding me 😭. But we'll leave the SDL part for later. We must build the game logic first! That's the whole vibe check.

One of the traps of game programming is focusing too much on the interface. If we start with a simpler simulation, we can worry about the presentation later. trust. πŸŽ€

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???" πŸ˜­πŸ’€


πŸ›Έ CONTROLLING THE SHIP πŸ›Έ

The problem with our first spaceship is that it had no controls! Not very main character energy of it.

So, let's fix this problem, making the spaceship scriptable. (We could write some code to handle keyboard and joysticks now, but a 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. iconic πŸŽ€

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


🌈 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... πŸ‘€

🎨 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": (images/background.jpg and images/ship.png). πŸ–ΌοΈβœ¨


πŸ‘‘ 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 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"). obsessed with that actually ✨

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. πŸŒ™πŸš€πŸ’–


Copyright 2009 Nelson Ferraz, all rights reserved.

Updated and maintained by the SDL Perl project. See "AUTHORS" in SDL.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


okay that's the whole page bestie, mwah πŸ’‹βœ¨ This one's from the perl v5.42.3 days, dated 2026-08-19, and it's filed under pods::...Lander(3pm) β€” go build your lunar lander, you're gonna eat πŸ«ΆπŸŽ€πŸŒ™

πŸ“¦ where this page comes from