First commit of SDL_Perl-2.1.3
[sdlgit/SDL_perl.git] / lib / SDL / Tutorial / Animation.pm
1 package SDL::Tutorial::Animation;
2
3 use Pod::ToDemo <<'END_HERE';
4 use SDL::App;
5 use SDL::Rect;
6 use SDL::Color;
7
8 # change these values as necessary
9 my $title                                = 'My SDL Animation';
10 my ($width,      $height,      $depth)   = (  640,  480,   16 );
11 my ($bg_r,       $bg_g,        $bg_b)    = ( 0x00, 0x00, 0x00 );
12 my ($rect_r,     $rect_g,      $rect_b)  = ( 0x00, 0x00, 0xff ); 
13 my ($rect_width, $rect_height, $rect_y)  = (  100,  100,  190 );
14
15 my $app = SDL::App->new(
16         -width  => $width,
17         -height => $height,
18         -depth  => $depth,
19 );
20
21 my $color = SDL::Color->new(
22         -r => $rect_r,
23         -g => $rect_g,
24         -b => $rect_b,
25 );
26
27 my $bg_color = SDL::Color->new(
28         -r => $bg_r,
29         -g => $bg_g,
30         -b => $bg_b,
31 );
32
33 my $background = SDL::Rect->new(
34         -width  => $width,
35         -height => $height,
36 );
37
38 my $rect = create_rect();
39
40 # your code here, perhaps
41 for my $x (0 .. 640)
42 {
43         $rect->x( $x );
44         draw_frame( $app,
45                 bg   => $background, bg_color   => $bg_color,
46                 rect => $rect,       rect_color => $color,
47         );
48 }
49
50 # remove this line
51 sleep 2;
52
53 # XXX - if you know why I need to create a new rect here, please tell me!
54 $rect        = create_rect();
55 my $old_rect = create_rect();
56
57 # your code also here, perhaps
58 for my $x (0 .. 640)
59 {
60         $rect->x( $x );
61         draw_undraw_rect( $app,
62                 rect       => $rect,  old_rect => $old_rect,
63                 rect_color => $color, bg_color => $bg_color, 
64         );
65         $old_rect->x( $x );
66 }
67
68 # your code almost certainly follows; remove this line
69 sleep 2;
70
71 sub create_rect
72 {
73         return SDL::Rect->new(
74                 -height => $rect_height,
75                 -width  => $rect_width,
76                 -x      => 0,
77                 -y      => $rect_y,
78         );
79 }
80
81 sub draw_frame
82 {
83         my ($app, %args) = @_;
84
85         $app->fill(   $args{bg},   $args{bg_color}   );
86         $app->fill(   $args{rect}, $args{rect_color} );
87         $app->update( $args{bg} );
88 }
89
90 sub draw_undraw_rect
91 {
92         my ($app, %args) = @_;
93
94         $app->fill(   $args{old_rect}, $args{bg_color}   );
95         $app->fill(   $args{rect},     $args{rect_color} );
96         $app->update( $args{old_rect} );
97         $app->update( $args{rect} );
98 }
99 END_HERE
100
101 1;
102 __END__
103
104 =head1 NAME
105
106 SDL::Tutorial::Animation
107
108 =head1 SYNOPSIS
109
110         # to read this tutorial
111         $ perldoc SDL::Tutorial::Animation
112
113         # to create a demo animation program based on this tutorial
114         $ perl -MSDL::Tutorial::Animation=sdl_anim.pl -e 1
115
116 =head1 ANIMATING A RECTANGLE
117
118 Now that you can display a rectangle on the screen, the next step is to animate
119 that rectangle.  As with movies, there's no actual motion.  Computer animations are just very very fast slideshows.  The hard work is creating nearly identical images in every slide (or frame, in graphics terms).
120
121 Okay, it's not that difficult.
122
123 There is one small difficulty to address, however.  Once you blit one surface
124 onto another, the destination is changed permanently.  There's no concept of
125 layers here unless you write it yourself.  If you fail to take this into
126 account (and just about everyone does at first), you'll end up with blurry
127 graphics moving around on the screen.
128
129 There are two approaches to solve this problem, redrawing the screen on every
130 frame and saving and restoring the background for every object drawn.
131
132 =head2 Redrawing the Screen
133
134 Since you have to draw the screen in the right order once to start with it's
135 pretty easy to make this into a loop and redraw things in the right order for
136 every frame.  Given a L<SDL::App> object C<$app>, a L<SDL::Rect> C<$rect>, and
137 a L<SDL::Color> C<$color>, you only have to create a new SDL::Rect C<$bg>,
138 representing the whole of the background surface and a new SDL::Color
139 C<$bg_color>, representing the background color.  You can write a
140 C<draw_frame()> function as follows:
141
142         sub draw_frame
143         {
144                 my ($app, %args) = @_;
145
146                 $app->fill( $args{ bg }, $args{ bg_color } );
147                 $app->fill( $args{rect}, $args{rect_color} );
148                 $app->update( $args{bg} );
149         }
150
151 Since you can change the C<x> and C<y> coordinates of a rect with the C<x()>
152 and C<y()> methods, you can move a rectangle across the screen with a loop like
153 this:
154
155         for my $x (0 .. 640)
156         {
157                 $rect->x( $x );
158                 draw_frame( $app,
159                         bg   => $bg,   bg_color   => $bg_color,
160                         rect => $rect, rect_color => $color,
161                 );
162         }
163
164 If C<$rect>'s starting y position is 190 and its height and width are 100, the
165 rectangle (er, square) will move across the middle of the screen.
166
167 Provided you can keep track of the proper order in which to redraw rectangles
168 and provided you don't need the optimal speed necessary (since blitting every
169 object takes more work than just blitting the portions you need), this works
170 quite well.
171
172 =head2 Undrawing the Updated Rectangle
173
174 If you need more speed or want to make a different complexity tradeoff, you can
175 take a snapshot of the destination rectangle I<before> you blit onto it.  That
176 way, when you need to redraw, you can blit the old snapshot back before
177 blitting to the new position.
178
179 B<Note:>  I have no idea how this will work in the face of alpha blending,
180 which, admittedly, I haven't even mentioned yet.  If you don't know what this
181 means, forget it.  If you do know what this means and know why I'm waving my
182 hands here, feel free to explain what should and what does happen and why.  :)
183
184 With this technique, the frame-drawing subroutine has to be a little more
185 complicated.  Instead of the background rect, it needs a rect for the previous
186 position.  It also needs to do two updates (or must perform some scary math to
187 figure out the rectangle of the correct size to C<update()>.  No thanks!).
188
189         sub undraw_redraw_rect
190         {
191                 my ($app, %args) = @_;
192
193                 $app->fill(   $args{old_rect}, $args{bg_color}   );
194                 $app->fill(   $args{rect],     $args{rect_color} );
195                 $app->update( $args{old_rect}, $args{rect}       );
196         }
197
198 We'll need to create a new SDL::Rect, C<$old_rect>, that is a duplicate of
199 C<$rect>, at the same position at first.  You should already know how to do
200 this.
201
202 As before, the loop to call C<undraw_redraw_rect()> would look something like:
203
204         for my $x (0 .. 640)
205         {
206                 $rect->x( $x );
207
208                 undraw_redraw_rect( $app,
209                         rect       => $rect,  old_rect => $old_rect,
210                         rect_color => $color, bg_color => $bgcolor,
211                 );
212
213                 $old_rect->x( $x );
214         }
215
216 If you run this code, you'll probably notice that it's tremendously faster than
217 the previous version.  It may be too fast, where the alternate technique was
218 just fast enough.  There are a couple of good ways to set a fixed animation
219 speed regardless of the speed of the processor and graphics hardware (provided
220 they're good enough, which is increasingly often the case), and we'll get to
221 them soon.
222
223 =head1 SEE ALSO
224
225 =over 4
226
227 =item L<SDL::Tutorial::Drawing>
228
229 basic drawing with SDL Perl
230
231 =item L<SDL::Tutorial::Images>
232
233 animating images
234
235 =back
236
237 =head1 AUTHOR
238
239 chromatic, E<lt>chromatic@wgz.orgE<gt>
240
241 Written for and maintained by the Perl SDL project, L<http://sdl.perl.org/>.
242
243 =head1 BUGS
244
245 No known bugs.
246
247 =head1 COPYRIGHT
248
249 Copyright (c) 2003 - 2004, chromatic.  All rights reserved.  This module is
250 distributed under the same terms as Perl itself, in the hope that it is useful
251 but certainly under no guarantee.