5 # Copyright (C) 2005 David J. Goehrig <dgoehrig@cpan.org>
7 # ------------------------------------------------------------------------------
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.
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.
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
23 # ------------------------------------------------------------------------------
25 # Please feel free to send questions, suggestions or improvements to:
31 package SDL::Tutorial::Animation;
39 # change these values as necessary
40 my $title = 'My SDL Animation';
41 my ($width, $height, $depth) = ( 640, 480, 16 );
42 my ($bg_r, $bg_g, $bg_b) = ( 0x00, 0x00, 0x00 );
43 my ($rect_r, $rect_g, $rect_b) = ( 0x00, 0x00, 0xff );
44 my ($rect_width, $rect_height, $rect_y) = ( 100, 100, 190 );
46 my $app = SDL::App->new(
52 my $color = SDL::Color->new(
58 my $bg_color = SDL::Color->new(
64 my $background = SDL::Rect->new(
69 my $rect = create_rect();
71 # your code here, perhaps
76 bg => $background, bg_color => $bg_color,
77 rect => $rect, rect_color => $color,
84 # XXX - if you know why I need to create a new rect here, please tell me!
85 $rect = create_rect();
86 my $old_rect = create_rect();
88 # your code also here, perhaps
92 draw_undraw_rect( $app,
93 rect => $rect, old_rect => $old_rect,
94 rect_color => $color, bg_color => $bg_color,
99 # your code almost certainly follows; remove this line
104 return SDL::Rect->new(
105 -height => $rect_height,
106 -width => $rect_width,
114 my ($app, %args) = @_;
116 $app->fill( $args{bg}, $args{bg_color} );
117 $app->fill( $args{rect}, $args{rect_color} );
118 $app->update( $args{bg} );
123 my ($app, %args) = @_;
125 $app->fill( $args{old_rect}, $args{bg_color} );
126 $app->fill( $args{rect}, $args{rect_color} );
127 $app->update( $args{old_rect} );
128 $app->update( $args{rect} );
137 SDL::Tutorial::Animation
141 # to read this tutorial
142 $ perldoc SDL::Tutorial::Animation
144 # to create a demo animation program based on this tutorial
145 $ perl -MSDL::Tutorial::Animation=sdl_anim.pl -e 1
147 =head1 ANIMATING A RECTANGLE
149 Now that you can display a rectangle on the screen, the next step is to animate
150 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).
152 Okay, it's not that difficult.
154 There is one small difficulty to address, however. Once you blit one surface
155 onto another, the destination is changed permanently. There's no concept of
156 layers here unless you write it yourself. If you fail to take this into
157 account (and just about everyone does at first), you'll end up with blurry
158 graphics moving around on the screen.
160 There are two approaches to solve this problem, redrawing the screen on every
161 frame and saving and restoring the background for every object drawn.
163 =head2 Redrawing the Screen
165 Since you have to draw the screen in the right order once to start with it's
166 pretty easy to make this into a loop and redraw things in the right order for
167 every frame. Given a L<SDL::App> object C<$app>, a L<SDL::Rect> C<$rect>, and
168 a L<SDL::Color> C<$color>, you only have to create a new SDL::Rect C<$bg>,
169 representing the whole of the background surface and a new SDL::Color
170 C<$bg_color>, representing the background color. You can write a
171 C<draw_frame()> function as follows:
175 my ($app, %args) = @_;
177 $app->fill( $args{ bg }, $args{ bg_color } );
178 $app->fill( $args{rect}, $args{rect_color} );
179 $app->update( $args{bg} );
182 Since you can change the C<x> and C<y> coordinates of a rect with the C<x()>
183 and C<y()> methods, you can move a rectangle across the screen with a loop like
190 bg => $bg, bg_color => $bg_color,
191 rect => $rect, rect_color => $color,
195 If C<$rect>'s starting y position is 190 and its height and width are 100, the
196 rectangle (er, square) will move across the middle of the screen.
198 Provided you can keep track of the proper order in which to redraw rectangles
199 and provided you don't need the optimal speed necessary (since blitting every
200 object takes more work than just blitting the portions you need), this works
203 =head2 Undrawing the Updated Rectangle
205 If you need more speed or want to make a different complexity tradeoff, you can
206 take a snapshot of the destination rectangle I<before> you blit onto it. That
207 way, when you need to redraw, you can blit the old snapshot back before
208 blitting to the new position.
210 B<Note:> I have no idea how this will work in the face of alpha blending,
211 which, admittedly, I haven't even mentioned yet. If you don't know what this
212 means, forget it. If you do know what this means and know why I'm waving my
213 hands here, feel free to explain what should and what does happen and why. :)
215 With this technique, the frame-drawing subroutine has to be a little more
216 complicated. Instead of the background rect, it needs a rect for the previous
217 position. It also needs to do two updates (or must perform some scary math to
218 figure out the rectangle of the correct size to C<update()>. No thanks!).
220 sub undraw_redraw_rect
222 my ($app, %args) = @_;
224 $app->fill( $args{old_rect}, $args{bg_color} );
225 $app->fill( $args{rect], $args{rect_color} );
226 $app->update( $args{old_rect}, $args{rect} );
229 We'll need to create a new SDL::Rect, C<$old_rect>, that is a duplicate of
230 C<$rect>, at the same position at first. You should already know how to do
233 As before, the loop to call C<undraw_redraw_rect()> would look something like:
239 undraw_redraw_rect( $app,
240 rect => $rect, old_rect => $old_rect,
241 rect_color => $color, bg_color => $bgcolor,
247 If you run this code, you'll probably notice that it's tremendously faster than
248 the previous version. It may be too fast, where the alternate technique was
249 just fast enough. There are a couple of good ways to set a fixed animation
250 speed regardless of the speed of the processor and graphics hardware (provided
251 they're good enough, which is increasingly often the case), and we'll get to
258 =item L<SDL::Tutorial::Drawing>
260 basic drawing with SDL Perl
262 =item L<SDL::Tutorial::Images>
270 chromatic, E<lt>chromatic@wgz.orgE<gt>
272 Written for and maintained by the Perl SDL project, L<http://sdl.perl.org/>.
280 Copyright (c) 2003 - 2004, chromatic. All rights reserved. This module is
281 distributed under the same terms as Perl itself, in the hope that it is useful
282 but certainly under no guarantee.