Fixed the pod path in archive
[sdlgit/SDL_perl.git] / lib / SDL / Tutorial / Images.pm
1 #!/usr/bin/env perl
2 #
3 # Images.pm
4 #
5 # Copyright (C) 2005 David J. Goehrig <dgoehrig@cpan.org>
6 #
7 # ------------------------------------------------------------------------------
8 #
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public
11 # License as published by the Free Software Foundation; either
12 # version 2.1 of the License, or (at your option) any later version.
13
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Lesser General Public License for more details.
18
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with this library; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 #
23 # ------------------------------------------------------------------------------
24 #
25 # Please feel free to send questions, suggestions or improvements to:
26 #
27 #       David J. Goehrig
28 #       dgoehrig@cpan.org
29 #
30
31 package SDL::Tutorial::Images;
32
33 use strict;
34 use SDL;
35 use warnings;
36
37 my %images;
38 BEGIN
39 {
40         %images = (
41         left => [qw(
42                 47 49 46 38 37 61 10 00 10 00 E7 00 00 00 00 00 01 01 01 02 02 02 03 03
43                 03 04 04 04 05 05 05 06 06 06 07 07 07 08 08 08 09 09 09 0A 0A 0A 0B 0B
44                 0B 0C 0C 0C 0D 0D 0D 0E 0E 0E 0F 0F 0F 10 10 10 11 11 11 12 12 12 13 13
45                 13 14 14 14 15 15 15 16 16 16 17 17 17 18 18 18 19 19 19 1A 1A 1A 1B 1B
46                 1B 1C 1C 1C 1D 1D 1D 1E 1E 1E 1F 1F 1F 20 20 20 21 21 21 22 22 22 23 23
47                 23 24 24 24 25 25 25 26 26 26 27 27 27 28 28 28 29 29 29 2A 2A 2A 2B 2B
48                 2B 2C 2C 2C 2D 2D 2D 2E 2E 2E 2F 2F 2F 30 30 30 31 31 31 32 32 32 33 33
49                 33 34 34 34 35 35 35 36 36 36 37 37 37 38 38 38 39 39 39 3A 3A 3A 3B 3B
50                 3B 3C 3C 3C 3D 3D 3D 3E 3E 3E 3F 3F 3F 40 40 40 41 41 41 42 42 42 43 43
51                 43 44 44 44 45 45 45 46 46 46 47 47 47 48 48 48 49 49 49 4A 4A 4A 4B 4B
52                 4B 4C 4C 4C 4D 4D 4D 4E 4E 4E 4F 4F 4F 50 50 50 51 51 51 52 52 52 53 53
53                 53 54 54 54 55 55 55 56 56 56 57 57 57 58 58 58 59 59 59 5A 5A 5A 5B 5B
54                 5B 5C 5C 5C 5D 5D 5D 5E 5E 5E 5F 5F 5F 60 60 60 61 61 61 62 62 62 63 63
55                 63 64 64 64 65 65 65 66 66 66 67 67 67 68 68 68 69 69 69 6A 6A 6A 6B 6B
56                 6B 6C 6C 6C 6D 6D 6D 6E 6E 6E 6F 6F 6F 70 70 70 71 71 71 72 72 72 73 73
57                 73 74 74 74 75 75 75 76 76 76 77 77 77 78 78 78 79 79 79 7A 7A 7A 7B 7B
58                 7B 7C 7C 7C 7D 7D 7D 7E 7E 7E 7F 7F 7F 80 80 80 81 81 81 82 82 82 83 83
59                 83 84 84 84 85 85 85 86 86 86 87 87 87 88 88 88 89 89 89 8A 8A 8A 8B 8B
60                 8B 8C 8C 8C 8D 8D 8D 8E 8E 8E 8F 8F 8F 90 90 90 91 91 91 92 92 92 93 93
61                 93 94 94 94 95 95 95 96 96 96 97 97 97 98 98 98 99 99 99 9A 9A 9A 9B 9B
62                 9B 9C 9C 9C 9D 9D 9D 9E 9E 9E 9F 9F 9F A0 A0 A0 A1 A1 A1 A2 A2 A2 A3 A3
63                 A3 A4 A4 A4 A5 A5 A5 A6 A6 A6 A7 A7 A7 A8 A8 A8 A9 A9 A9 AA AA AA AB AB
64                 AB AC AC AC AD AD AD AE AE AE AF AF AF B0 B0 B0 B1 B1 B1 B2 B2 B2 B3 B3
65                 B3 B4 B4 B4 B5 B5 B5 B6 B6 B6 B7 B7 B7 B8 B8 B8 B9 B9 B9 BA BA BA BB BB
66                 BB BC BC BC BD BD BD BE BE BE BF BF BF C0 C0 C0 C1 C1 C1 C2 C2 C2 C3 C3
67                 C3 C4 C4 C4 C5 C5 C5 C6 C6 C6 C7 C7 C7 C8 C8 C8 C9 C9 C9 CA CA CA CB CB
68                 CB CC CC CC CD CD CD CE CE CE CF CF CF D0 D0 D0 D1 D1 D1 D2 D2 D2 D3 D3
69                 D3 D4 D4 D4 D5 D5 D5 D6 D6 D6 D7 D7 D7 D8 D8 D8 D9 D9 D9 DA DA DA DB DB
70                 DB DC DC DC DD DD DD DE DE DE DF DF DF E0 E0 E0 E1 E1 E1 E2 E2 E2 E3 E3
71                 E3 E4 E4 E4 E5 E5 E5 E6 E6 E6 E7 E7 E7 E8 E8 E8 E9 E9 E9 EA EA EA EB EB
72                 EB EC EC EC ED ED ED EE EE EE EF EF EF F0 F0 F0 F1 F1 F1 F2 F2 F2 F3 F3
73                 F3 F4 F4 F4 F5 F5 F5 F6 F6 F6 F7 F7 F7 F8 F8 F8 F9 F9 F9 FA FA FA FB FB
74                 FB FC FC FC FD FD FD FE FE FE FF FF FF 2C 00 00 00 00 10 00 10 00 00 08
75                 36 00 FF 09 1C 48 B0 A0 C1 83 08 13 22 04 C0 10 80 C2 7F 0C 05 46 4C E8
76                 70 60 C5 85 15 27 52 6C A8 30 E3 45 8C 0D 39 76 FC 38 F2 A1 44 91 1B 4F
77                 82 24 88 D2 64 C1 80 00 3B
78         )],
79         center => [qw(
80                 47 49 46 38 37 61 10 00 10 00 E7 00 00 00 00 00 01 01 01 02 02 02 03 03
81                 03 04 04 04 05 05 05 06 06 06 07 07 07 08 08 08 09 09 09 0A 0A 0A 0B 0B
82                 0B 0C 0C 0C 0D 0D 0D 0E 0E 0E 0F 0F 0F 10 10 10 11 11 11 12 12 12 13 13
83                 13 14 14 14 15 15 15 16 16 16 17 17 17 18 18 18 19 19 19 1A 1A 1A 1B 1B
84                 1B 1C 1C 1C 1D 1D 1D 1E 1E 1E 1F 1F 1F 20 20 20 21 21 21 22 22 22 23 23
85                 23 24 24 24 25 25 25 26 26 26 27 27 27 28 28 28 29 29 29 2A 2A 2A 2B 2B
86                 2B 2C 2C 2C 2D 2D 2D 2E 2E 2E 2F 2F 2F 30 30 30 31 31 31 32 32 32 33 33
87                 33 34 34 34 35 35 35 36 36 36 37 37 37 38 38 38 39 39 39 3A 3A 3A 3B 3B
88                 3B 3C 3C 3C 3D 3D 3D 3E 3E 3E 3F 3F 3F 40 40 40 41 41 41 42 42 42 43 43
89                 43 44 44 44 45 45 45 46 46 46 47 47 47 48 48 48 49 49 49 4A 4A 4A 4B 4B
90                 4B 4C 4C 4C 4D 4D 4D 4E 4E 4E 4F 4F 4F 50 50 50 51 51 51 52 52 52 53 53
91                 53 54 54 54 55 55 55 56 56 56 57 57 57 58 58 58 59 59 59 5A 5A 5A 5B 5B
92                 5B 5C 5C 5C 5D 5D 5D 5E 5E 5E 5F 5F 5F 60 60 60 61 61 61 62 62 62 63 63
93                 63 64 64 64 65 65 65 66 66 66 67 67 67 68 68 68 69 69 69 6A 6A 6A 6B 6B
94                 6B 6C 6C 6C 6D 6D 6D 6E 6E 6E 6F 6F 6F 70 70 70 71 71 71 72 72 72 73 73
95                 73 74 74 74 75 75 75 76 76 76 77 77 77 78 78 78 79 79 79 7A 7A 7A 7B 7B
96                 7B 7C 7C 7C 7D 7D 7D 7E 7E 7E 7F 7F 7F 80 80 80 81 81 81 82 82 82 83 83
97                 83 84 84 84 85 85 85 86 86 86 87 87 87 88 88 88 89 89 89 8A 8A 8A 8B 8B
98                 8B 8C 8C 8C 8D 8D 8D 8E 8E 8E 8F 8F 8F 90 90 90 91 91 91 92 92 92 93 93
99                 93 94 94 94 95 95 95 96 96 96 97 97 97 98 98 98 99 99 99 9A 9A 9A 9B 9B
100                 9B 9C 9C 9C 9D 9D 9D 9E 9E 9E 9F 9F 9F A0 A0 A0 A1 A1 A1 A2 A2 A2 A3 A3
101                 A3 A4 A4 A4 A5 A5 A5 A6 A6 A6 A7 A7 A7 A8 A8 A8 A9 A9 A9 AA AA AA AB AB
102                 AB AC AC AC AD AD AD AE AE AE AF AF AF B0 B0 B0 B1 B1 B1 B2 B2 B2 B3 B3
103                 B3 B4 B4 B4 B5 B5 B5 B6 B6 B6 B7 B7 B7 B8 B8 B8 B9 B9 B9 BA BA BA BB BB
104                 BB BC BC BC BD BD BD BE BE BE BF BF BF C0 C0 C0 C1 C1 C1 C2 C2 C2 C3 C3
105                 C3 C4 C4 C4 C5 C5 C5 C6 C6 C6 C7 C7 C7 C8 C8 C8 C9 C9 C9 CA CA CA CB CB
106                 CB CC CC CC CD CD CD CE CE CE CF CF CF D0 D0 D0 D1 D1 D1 D2 D2 D2 D3 D3
107                 D3 D4 D4 D4 D5 D5 D5 D6 D6 D6 D7 D7 D7 D8 D8 D8 D9 D9 D9 DA DA DA DB DB
108                 DB DC DC DC DD DD DD DE DE DE DF DF DF E0 E0 E0 E1 E1 E1 E2 E2 E2 E3 E3
109                 E3 E4 E4 E4 E5 E5 E5 E6 E6 E6 E7 E7 E7 E8 E8 E8 E9 E9 E9 EA EA EA EB EB
110                 EB EC EC EC ED ED ED EE EE EE EF EF EF F0 F0 F0 F1 F1 F1 F2 F2 F2 F3 F3
111                 F3 F4 F4 F4 F5 F5 F5 F6 F6 F6 F7 F7 F7 F8 F8 F8 F9 F9 F9 FA FA FA FB FB
112                 FB FC FC FC FD FD FD FE FE FE FF FF FF 2C 00 00 00 00 10 00 10 00 00 08
113                 36 00 FF 09 1C 48 B0 A0 C1 83 08 13 26 04 C0 10 80 C2 7F 0C 05 46 5C 48
114                 D0 E1 42 8B 13 2F 66 54 B8 F1 60 C3 8F 16 2F 3E 1C D8 11 E1 C7 87 13 4B
115                 4A DC D8 70 E4 C1 80 00 3B
116         )],
117         right => [qw(
118                 47 49 46 38 37 61 10 00 10 00 E7 00 00 00 00 00 01 01 01 02 02 02 03 03
119                 03 04 04 04 05 05 05 06 06 06 07 07 07 08 08 08 09 09 09 0A 0A 0A 0B 0B
120                 0B 0C 0C 0C 0D 0D 0D 0E 0E 0E 0F 0F 0F 10 10 10 11 11 11 12 12 12 13 13
121                 13 14 14 14 15 15 15 16 16 16 17 17 17 18 18 18 19 19 19 1A 1A 1A 1B 1B
122                 1B 1C 1C 1C 1D 1D 1D 1E 1E 1E 1F 1F 1F 20 20 20 21 21 21 22 22 22 23 23
123                 23 24 24 24 25 25 25 26 26 26 27 27 27 28 28 28 29 29 29 2A 2A 2A 2B 2B
124                 2B 2C 2C 2C 2D 2D 2D 2E 2E 2E 2F 2F 2F 30 30 30 31 31 31 32 32 32 33 33
125                 33 34 34 34 35 35 35 36 36 36 37 37 37 38 38 38 39 39 39 3A 3A 3A 3B 3B
126                 3B 3C 3C 3C 3D 3D 3D 3E 3E 3E 3F 3F 3F 40 40 40 41 41 41 42 42 42 43 43
127                 43 44 44 44 45 45 45 46 46 46 47 47 47 48 48 48 49 49 49 4A 4A 4A 4B 4B
128                 4B 4C 4C 4C 4D 4D 4D 4E 4E 4E 4F 4F 4F 50 50 50 51 51 51 52 52 52 53 53
129                 53 54 54 54 55 55 55 56 56 56 57 57 57 58 58 58 59 59 59 5A 5A 5A 5B 5B
130                 5B 5C 5C 5C 5D 5D 5D 5E 5E 5E 5F 5F 5F 60 60 60 61 61 61 62 62 62 63 63
131                 63 64 64 64 65 65 65 66 66 66 67 67 67 68 68 68 69 69 69 6A 6A 6A 6B 6B
132                 6B 6C 6C 6C 6D 6D 6D 6E 6E 6E 6F 6F 6F 70 70 70 71 71 71 72 72 72 73 73
133                 73 74 74 74 75 75 75 76 76 76 77 77 77 78 78 78 79 79 79 7A 7A 7A 7B 7B
134                 7B 7C 7C 7C 7D 7D 7D 7E 7E 7E 7F 7F 7F 80 80 80 81 81 81 82 82 82 83 83
135                 83 84 84 84 85 85 85 86 86 86 87 87 87 88 88 88 89 89 89 8A 8A 8A 8B 8B
136                 8B 8C 8C 8C 8D 8D 8D 8E 8E 8E 8F 8F 8F 90 90 90 91 91 91 92 92 92 93 93
137                 93 94 94 94 95 95 95 96 96 96 97 97 97 98 98 98 99 99 99 9A 9A 9A 9B 9B
138                 9B 9C 9C 9C 9D 9D 9D 9E 9E 9E 9F 9F 9F A0 A0 A0 A1 A1 A1 A2 A2 A2 A3 A3
139                 A3 A4 A4 A4 A5 A5 A5 A6 A6 A6 A7 A7 A7 A8 A8 A8 A9 A9 A9 AA AA AA AB AB
140                 AB AC AC AC AD AD AD AE AE AE AF AF AF B0 B0 B0 B1 B1 B1 B2 B2 B2 B3 B3
141                 B3 B4 B4 B4 B5 B5 B5 B6 B6 B6 B7 B7 B7 B8 B8 B8 B9 B9 B9 BA BA BA BB BB
142                 BB BC BC BC BD BD BD BE BE BE BF BF BF C0 C0 C0 C1 C1 C1 C2 C2 C2 C3 C3
143                 C3 C4 C4 C4 C5 C5 C5 C6 C6 C6 C7 C7 C7 C8 C8 C8 C9 C9 C9 CA CA CA CB CB
144                 CB CC CC CC CD CD CD CE CE CE CF CF CF D0 D0 D0 D1 D1 D1 D2 D2 D2 D3 D3
145                 D3 D4 D4 D4 D5 D5 D5 D6 D6 D6 D7 D7 D7 D8 D8 D8 D9 D9 D9 DA DA DA DB DB
146                 DB DC DC DC DD DD DD DE DE DE DF DF DF E0 E0 E0 E1 E1 E1 E2 E2 E2 E3 E3
147                 E3 E4 E4 E4 E5 E5 E5 E6 E6 E6 E7 E7 E7 E8 E8 E8 E9 E9 E9 EA EA EA EB EB
148                 EB EC EC EC ED ED ED EE EE EE EF EF EF F0 F0 F0 F1 F1 F1 F2 F2 F2 F3 F3
149                 F3 F4 F4 F4 F5 F5 F5 F6 F6 F6 F7 F7 F7 F8 F8 F8 F9 F9 F9 FA FA FA FB FB
150                 FB FC FC FC FD FD FD FE FE FE FF FF FF 2C 00 00 00 00 10 00 10 00 00 08
151                 3A 00 FF 09 1C 48 B0 A0 C1 83 08 13 2A 04 C0 10 80 C2 7F 0C 05 46 4C E8
152                 70 60 45 84 13 27 52 6C F8 50 62 C5 8B 05 1B 8A 04 79 50 E3 43 93 1B 51
153                 1A CC 48 D2 A2 49 8E 1D 0B 06 04 00 3B
154         )],
155 );
156 }
157
158 use Pod::ToDemo sub
159 {
160         (undef, my $filename) = @_;
161         (my $imagebase        = $filename) =~ s/\.\w+$//;
162         my @img_files         = map { $imagebase . "_$_.gif" }
163                 qw( left center right );
164         my $demo_source       = <<'END_HERE';
165 package Walker;
166
167 sub new
168 {
169         my ($class, @images) = @_;
170         my @frames           = map { SDL::Surface->new( -name => $_ ) } @images;
171         my $frame_rect       = SDL::Rect->new(
172                 -height => $frames[0]->height(),
173                 -width  => $frames[0]->width(),
174                 -x      => 0,
175                 -y      => 0,
176         );
177         my $self             = 
178         {
179                 frames      => \@frames,
180                 frame_rect  => $frame_rect,
181         };
182         bless $self, $class;
183 }
184
185 sub frames
186 {
187         my $self        = shift;
188         $self->{frames} = shift if @_;
189         $self->{frames};
190 }
191
192 sub frame_rect
193 {
194         my $self            = shift;
195         $self->{frame_rect} = shift if @_;
196         $self->{frame_rect};
197 }
198
199 sub next_frame
200 {
201         my $self   = shift;
202         my $frames = $self->frames();
203         my $frame  = shift @$frames;
204
205         push @$frames, $frame;
206         $self->frames( $frames );
207
208         return $frame;
209 }
210
211 package main;
212
213 use strict;
214
215 use SDL;
216 use SDL::App;
217 use SDL::Surface;
218 use SDL::Color;
219
220 # change these values as necessary
221 my $title                                = 'My SDL Animation';
222 my ($width,      $height,      $depth)   = (  640,  480,   16 );
223 my ($bg_r,       $bg_g,        $bg_b)    = ( 0xff, 0xff, 0xff );
224 my ($start_x,    $end_x)                 = (   20,  600       );
225 my $sleep_msec                           = 0.05;
226
227 my $app = SDL::App->new(
228         -width  => $width,
229         -height => $height,
230         -depth  => $depth,
231 );
232
233 my $bg_color = SDL::Color->new(
234         -r => $bg_r,
235         -g => $bg_g,
236         -b => $bg_b,
237 );
238
239 my $background = SDL::Rect->new(
240         -width  => $width,
241         -height => $height,
242 );
243
244 my $pos = SDL::Rect->new(
245         -width  => 16,
246         -height => 16,
247         -x      => 0,
248         -y      => 240,
249 );
250
251 my $walker = Walker->new(qw(
252 END_HERE
253
254 $demo_source .= join( ' ', @img_files ) . "));" . <<'END_HERE';
255
256 for my $x ( $start_x .. $end_x )
257 {
258         draw_background( $app, $background, $bg_color );
259         $pos->x( $x );
260         draw_walker( $walker, $app, $pos );
261         $app->update( $background );
262         select( undef, undef, undef, $sleep_msec );
263 }
264
265 # you'll want to remove this
266 sleep 2;
267
268 sub draw_background
269 {
270         my ($app, $background, $bg_color) = @_;
271         $app->fill( $background, $bg_color );
272 }
273
274 sub draw_walker
275 {
276         my ($walker, $app, $pos) = @_;
277         my $frame                = $walker->next_frame();
278         my $frame_rect           = $walker->frame_rect();
279         $frame->blit( $frame_rect, $app, $pos );
280 }
281 END_HERE
282
283         Pod::ToDemo::write_demo( $filename, "#$^X\n$demo_source" );
284         write_files( $imagebase );
285 };
286                 
287 sub write_files
288 {
289         my $imagebase = shift;
290
291         for my $image (qw( left center right ))
292         {
293                 my $file = join('', map { chr( hex( $_ ) ) } @{ $images{ $image } });
294                 write_file( $imagebase . "_$image" . '.gif', $file );
295         }
296 }
297
298 sub write_file
299 {
300     my ($file, $contents) = @_;
301
302         die "Cowardly refusing to overwrite '$file'\n" if -e $file;
303         open my $out, '>', $file or die "Cannot write '$file': $!\n";
304         binmode $out;
305         print $out $contents;
306 }
307
308 __END__
309
310 =head1 NAME
311
312 SDL::Tutorial::Images
313
314 =head1 SYNOPSIS
315
316         # to read this tutorial
317         $ perldoc SDL::Tutorial::Images
318
319         # to create a demo animation program based on this tutorial
320         $ perl -MSDL::Tutorial::Images=sdl_images.pl -e 1
321
322 =head1 ANIMATING IMAGES
323
324 Since you're already familiar with the concepts behind animation, it's time to
325 learn how to work with images.  As usual, the important point is that computer animation is just I<simulating> motion by painting several slightly different frames to the screen every second.
326
327 There are two ways to vary an image on screen.  One is to change its
328 coordinates so it's at a slightly different position.  This is very easy to do;
329 it's just like animating a rectangle.  The other way is to change the image
330 itself so it's slightly different.  This is a little more difficult, as you'll
331 need to draw the alternate image beforehand somehow.
332
333 =head2 Loading Images
334
335 As usual, start with an L<SDL::App> object representing the image window.  Then
336 preload the image file.  This is easy; just pass the C<name> parameter to the
337 L<SDL::Surface> constructor:
338
339         use SDL::Surface;
340
341         my $frame = SDL::Surface->new( -name => 'frame1.png' );
342
343 B<Note:> you'll need to have compiled SDL Perl (and probably SDL) to support
344 JPEG and PNG files for this to work.
345
346 That's it; now you have an SDL::Surface object containing the image.  You can
347 use the C<height()>, C<width()>, and C<bpp()> methods to retrieve its height,
348 width, and bits per pixel, if you need them.
349
350 =head2 Displaying Images
351
352 Drawing an image onto the screen requires blitting it from one surface to
353 another.  (Remember, "blitting" means copying bits in memory.)  The C<blit()>
354 method of SDL::Surface objects comes in handy.  Its arguments are a little odd,
355 though.  Assuming C<$app> is the SDL::App object, as usual:
356
357         use SDL::Rect;
358
359         my $frame_rect = SDL::Rect->new(
360                 -height => $frame->height(),
361                 -width  => $frame->width(),
362                 -x      => 0,
363                 -y      => 0,
364         );
365
366         my $dest_rect  = SDL::Rect->new(
367                 -height => $frame->height(),
368                 -width  => $frame->width(),
369                 -x      => 0,
370                 -y      => 0,
371         );
372
373         $frame->blit( $frame_rect, $app, $dest_rect );
374         $app->update( $dest_rect );
375
376 Here we have two L<SDL::Rect> objects which represent rectangular regions of a
377 Surface.  C<$frame_rect> represents the entire area of C<$frame>, while
378 C<$dest_rect> represents the area of the main window in which to blit the
379 frame.  This may be clearer with more descriptive variable names:
380
381         $source_surface->blit(
382                 $area_of_source_to_blit,
383                 $destination_surface,
384                 $destination_area
385         );
386
387 As usual, call C<update()> on C<$app> to see the change.
388
389 Requiring the source and destination Rect objects may seem tedious in this
390 simple example, but it's highly useful for copying only part of surface to part
391 of another.  For example, animating this image is a matter of changing the C<x>
392 and C<y> coordinates of C<$dest_rect>:
393
394         for my $x ( 1 .. 100 )
395         {
396                 $dest_rect->x( $x );
397                 $frame->blit( $frame_rect, $app, $dest_rect );
398                 $app->update( $dest_rect );
399         }
400
401 Of course, you'll have to redraw all or part of the screen to avoid artifacts,
402 as discussed in the previous tutorial.
403
404 =head2 Multi-Image Animation
405
406 That covers moving a single image around the screen.  What if you want
407 something more?  For example, what if you want to animate a stick figure
408 walking?
409
410 You'll need several frames, just as in a flip-book.  Each frame should be slightly different than the one before it.  It's probably handy to encapsulate all of this in a C<Walker> class:
411
412         package Walker;
413
414         use SDL::Surface;
415
416         sub new
417         {
418                 my ($class, @images) = @_;
419                 my $self = [ map { SDL::Surface->new( -name => $_ ) } @images ];
420
421                 bless $self, $class;
422         }
423
424         sub next_frame
425         {
426                 my $self  = shift;
427                 my $frame = shift @$self;
428
429                 push @$self, $frame;
430                 return $frame;
431         }
432
433 To use this class, instantiate an object:
434
435         my $walker = Walker->new( 'frame1.png', 'frame2.png', 'frame3.png' );
436
437 Then call C<next_frame()> within the loop:
438
439         for my $x ( 1 .. 100 )
440         {
441                 my $frame = $walker->next_frame();
442
443                 $dest_rect->x( $x );
444                 $frame->blit( $frame_rect, $app, $dest_rect );
445                 $app->update( $dest_rect );
446         }
447
448 Again, the rest of the frame drawing is missing from this example so as not to
449 distract from this technique.  You'll probably want to abstract the undrawing
450 and redrawing into a separate subroutine so you don't have to worry about it
451 every time.
452
453 It'd be easy to make C<next_frame()> much smarter, selecting an image
454 appropriate to the direction of travel, using a bored animation when the
455 character is no longer moving, or adding other characteristics to the
456 character.  As you can see, the hard part of this technique is generating the
457 images beforehand.  That can add up to a tremendous amount of art and that's
458 one reason for the popularity of 3D models... but that's another tutorial much
459 further down the road.
460
461 More importantly, it's time to discuss how to make these animations run more
462 smoothly.  More on that next time.
463
464 =head1 SEE ALSO
465
466 =over 4
467
468 =item L<SDL::Tutorial>
469
470 basic SDL tutorial
471
472 =item L<SDL::Tutorial::Animation>
473
474 non-image animation
475
476 =back
477
478 =head1 AUTHOR
479
480 chromatic, E<lt>chromatic@wgz.orgE<gt>
481
482 Written for and maintained by the Perl SDL project, L<http://sdl.perl.org/>.
483
484 =head1 BUGS
485
486 No known bugs.
487
488 =head1 COPYRIGHT
489
490 Copyright (c) 2004, chromatic.  All rights reserved.  This module is
491 distributed under the same terms as Perl itself, in the hope that it is useful
492 but certainly under no guarantee.