fixed blit with new rect
[sdlgit/SDL_perl.git] / lib / SDL / Game / Rect.pm
1 package SDL::Game::Rect;
2 use strict;
3 use warnings;
4 use Carp;
5 use base 'SDL::Rect';
6
7 our $VERSION = '0.01';
8
9 sub new {
10     my $class = shift;
11     my $x = shift || 0;
12     my $y = shift || 0;
13     my $w = shift || 0;
14     my $h = shift || 0;
15
16     my $self = $class->SUPER::new($x, $y, $w, $h);
17     unless ($$self) {
18         #require Carp;
19         croak SDL::GetError();
20     }
21     bless $self, $class;
22     return $self;
23 }
24
25 #############################
26 ## extra accessors
27 #############################
28 sub bottom {
29     my ($self, $val) = (@_);
30     if (defined $val) {
31         $self->top($val - $self->height); # y = val - height
32     }
33     return $self->top + $self->height; # y + height
34 }
35
36 sub right {
37     my ($self, $val) = (@_);
38     if (defined $val) {
39         $self->left($val - $self->width); # x = val - width
40     }
41     return $self->left + $self->width; # x + width
42 }
43
44 sub centerx {
45     my ($self, $val) = (@_);
46     if (defined $val) {
47         $self->left($val - ($self->width >> 1)); # x = val - (width/2)
48     }
49     return $self->left + ($self->width >> 1); # x + (width/2)
50 }
51
52 sub centery {
53     my ($self, $val) = (@_);
54     if (defined $val) {
55         $self->top($val - ($self->height >> 1)); # y = val - (height/2)
56     }
57     return $self->top + ($self->height >> 1); # y + (height/2)
58 }
59
60 sub size {
61     my ($self, $w, $h) = (@_);
62     
63     return ($self->width, $self->height)  # (width, height)
64         unless (defined $w or defined $h);
65         
66     if (defined $w) {
67         $self->width($w); # width
68     }
69     if (defined $h) {
70         $self->height($h); # height
71     }
72 }
73
74 sub topleft {
75     my ($self, $y, $x) = (@_);
76     
77     return ($self->top, $self->left) # (top, left)
78         unless (defined $y or defined $x);
79
80     if (defined $x) {
81         $self->left($x); # left
82     }
83     if (defined $y) {
84         $self->top($y); # top
85     }
86     return;
87 }
88
89 sub midleft {
90     my ($self, $centery, $x) = (@_);
91     
92     return ($self->top + ($self->height >> 1), $self->left) # (centery, left)
93         unless (defined $centery or defined $x);
94     
95     if (defined $x) {
96         $self->left($x); # left
97     }
98     if (defined $centery) {
99         $self->top($centery - ($self->height >> 1)); # y = centery - (height/2)
100     }
101     return;
102 }
103
104 sub bottomleft {
105     my ($self, $bottom, $x) = (@_);
106     
107     return ($self->top + $self->height, $self->left) # (bottom, left)
108         unless (defined $bottom or defined $x);
109
110     if (defined $x) {
111         $self->left($x); # left
112     }
113     if (defined $bottom) {
114         $self->top($bottom - $self->height); # y = bottom - height
115     }
116     return;
117 }
118
119 sub center {
120     my ($self, $centerx, $centery) = (@_);
121     
122     return ($self->left + ($self->width >> 1), $self->top + ($self->height >> 1))
123         unless (defined $centerx or defined $centery);
124
125     if (defined $centerx) {
126         $self->left($centerx - ($self->width >> 1)); # x = centerx - (width/2)        
127     }
128     if (defined $centery) {
129         $self->top($centery - ($self->height >> 1)); # y = centery - (height/2)
130     }
131     return;
132 }
133
134 sub topright {
135     my ($self, $y, $right) = (@_);
136     
137     return ($self->top, $self->left + $self->width) # (top, right)
138         unless (defined $y or defined $right);
139
140     if (defined $right) {
141         $self->left($right - $self->width); # x = right - width
142     }
143     if (defined $y) {
144         $self->top($y); # top
145     }
146     return;
147 }
148
149 sub midright {
150     my ($self, $centery, $right) = (@_);
151     
152     return ($self->top + ($self->height >> 1), $self->left + $self->width) # (centery, right)
153         unless (defined $centery or defined $right);
154     
155     if (defined $right) {
156         $self->left($right - $self->width); # x = right - width
157     }
158     if (defined $centery) {
159         $self->top($centery - ($self->height >> 1)); # y = centery - (height/2)
160     }
161     return;
162 }
163
164 sub bottomright {
165     my ($self, $bottom, $right) = (@_);
166     
167     return ($self->top + $self->height, $self->left + $self->width) # (bottom, right)
168         unless (defined $bottom or defined $right);
169
170     if (defined $right) {
171         $self->left($right - $self->width); # x = right - width
172     }
173     if (defined $bottom) {
174         $self->top($bottom - $self->height); # y = bottom - height
175     }
176     return;
177 }
178
179 sub midtop {
180     my ($self, $centerx, $y) = (@_);
181     
182     return ($self->left + ($self->width >> 1), $self->top) # (centerx, top)
183         unless (defined $centerx or defined $y);
184     
185     if (defined $y) {
186         $self->top($y); # top
187     }
188     if (defined $centerx) {
189         $self->left($centerx - ($self->width >> 1)); # x = centerx - (width/2)
190     }
191     return;
192 }
193
194 sub midbottom {
195     my ($self, $centerx, $bottom) = (@_);
196     
197     return ($self->left + ($self->width >> 1), $self->top + $self->height) # (centerx, bottom)
198         unless (defined $centerx or defined $bottom);
199     
200     if (defined $bottom) {
201         $self->top($bottom - $self->height); # y = bottom - height
202     }
203     if (defined $centerx) {
204         $self->left($centerx - ($self->width >> 1)); # x = centerx - (width/2)
205     }
206     return;    
207 }
208
209 ###############################
210 ## methods                   ##
211 ###############################
212
213 {
214     no strict 'refs';
215     *{'duplicate'} = *{copy};
216 }
217
218 sub copy {
219     my $self = shift;
220     return $self->new(
221         -top    => $self->top,
222         -left   => $self->left,
223         -width  => $self->width,
224         -height => $self->height,
225     );
226 }
227
228 sub move {
229     my ($self, $x, $y) = (@_);
230     if (not defined $x or not defined $y) {
231         #require Carp;
232         croak "must receive x and y positions as argument";
233     }
234     return $self->new(
235         -top    => $self->top + $y,
236         -left   => $self->left + $x,
237         -width  => $self->width,
238         -height => $self->height,
239     );
240 }
241
242 sub move_ip {
243     my ($self, $x, $y) = (@_);
244     if (not defined $x or not defined $y) {
245         #require Carp;
246         croak "must receive x and y positions as argument";
247     }
248     $self->x($self->x + $x);
249     $self->y($self->y + $y);
250     
251     return;
252 }
253
254 sub inflate {
255     my ($self, $x, $y) = (@_);
256     if (not defined $x or not defined $y) {
257         #require Carp;
258         croak "must receive x and y positions as argument";
259     }
260     
261     return $self->new(
262         -left   => $self->left   - ($x / 2),
263         -top    => $self->top    - ($y / 2),
264         -width  => $self->width  + $x,
265         -height => $self->height + $y,
266     );
267 }
268
269 sub inflate_ip {
270     my ($self, $x, $y) = (@_);
271     if (not defined $x or not defined $y) {
272         #require Carp;
273         croak "must receive x and y positions as argument";
274     }
275     
276     $self->x( $self->x - ($x / 2) );
277     $self->y( $self->y - ($y / 2) );
278     
279     $self->w( $self->w + $x );
280     $self->h( $self->h + $y );
281 }
282
283 sub _get_clamp_coordinates {
284     my ($self_pos, $self_len, $rect_pos, $rect_len) = (@_);
285
286     if ($self_len >= $rect_len) {
287         return $rect_pos + ($rect_len / 2) - ($self_len / 2);
288     }
289     elsif ($self_pos < $rect_pos) {
290         return $rect_pos;
291     }
292     elsif ( ($self_pos + $self_len) > ($rect_pos + $rect_len) ) {
293         return $rect_pos + $rect_len - $self_len;
294     }
295     else {
296         return $self_pos;
297     }
298 }
299
300 sub clamp {
301     my ($self, $rect) = (@_);
302     
303     unless ($rect->isa('SDL::Rect')) {
304         croak "must receive an SDL::Rect-based object";
305     }
306
307     my $x = _get_clamp_coordinates($self->x, $self->w, $rect->x, $rect->w);
308     my $y = _get_clamp_coordinates($self->y, $self->h, $rect->y, $rect->h);
309     
310     return $self->new($x, $y, $self->w, $self->h);
311 }
312
313 sub clamp_ip {
314     my ($self, $rect) = (@_);
315     
316     unless ($rect->isa('SDL::Rect')) {
317         croak "must receive an SDL::Rect-based object";
318     }
319
320     my $x = _get_clamp_coordinates($self->x, $self->w, $rect->x, $rect->w);
321     my $y = _get_clamp_coordinates($self->y, $self->h, $rect->y, $rect->h);
322     
323     $self->x($x);
324     $self->y($y);
325     
326     return;
327 }
328
329 sub _get_intersection_coordinates {
330     my ($self, $rect) = (@_);
331     my ($x, $y, $w, $h);
332     
333 INTERSECTION: 
334     {
335         ### Left
336         if (($self->x >= $rect->x) && ($self->x < ($rect->x + $rect->w))) {
337             $x = $self->x;
338         }
339         elsif (($rect->x >= $self->x) && ($rect->x < ($self->x + $self->w))) {
340             $x = $rect->x;
341         }
342         else {
343             last INTERSECTION;
344         }
345
346         ## Right
347         if ((($self->x + $self->w) > $rect->x) && (($self->x + $self->w) <= ($rect->x + $rect->w))) {
348             $w = ($self->x + $self->w) - $x;
349         }
350         elsif ((($rect->x + $rect->w) > $self->x) && (($rect->x + $rect->w) <= ($self->x + $self->w))) {
351             $w = ($rect->x + $rect->w) - $x;
352         }
353         else {
354             last INTERSECTION;
355         }
356
357         ## Top
358         if (($self->y >= $rect->y) && ($self->y < ($rect->y + $rect->h))) {
359             $y = $self->y;
360         }
361         elsif (($rect->y >= $self->y) && ($rect->y < ($self->y + $self->h))) {
362             $y = $rect->y;
363         }
364         else {
365             last INTERSECTION;
366         }
367
368         ## Bottom
369         if ((($self->y + $self->h) > $rect->y) && (($self->y + $self->h) <= ($rect->y + $rect->h))) {
370             $h = ($self->y + $self->h) - $y;
371         }
372         elsif ((($rect->y + $rect->h) > $self->y) && (($rect->y + $rect->h) <= ($self->y + $self->h))) {
373             $h = ($rect->y + $rect->h) - $y;
374         }
375         else {
376             last INTERSECTION;
377         }
378
379         return ($x, $y, $w, $h);
380     }
381     
382     # if we got here, the two rects do not intersect
383     return ($self->x, $self->y, 0, 0);
384
385 }
386
387 sub clip {
388     my ($self, $rect) = (@_);
389     
390     unless ($rect->isa('SDL::Rect')) {
391         croak "must receive an SDL::Rect-based object";
392     }
393
394     my ($x, $y, $w, $h) = _get_intersection_coordinates($self, $rect);
395     
396     return $self->new($x, $y, $w, $h);
397 }
398
399 sub clip_ip {
400     my ($self, $rect) = (@_);
401     
402     unless ($rect->isa('SDL::Rect')) {
403         croak "must receive an SDL::Rect-based object";
404     }
405
406     my ($x, $y, $w, $h) = _get_intersection_coordinates($self, $rect);
407     
408     $self->x($x);
409     $self->y($y);
410     $self->w($w);
411     $self->h($h);
412     
413     return;
414 }
415
416
417 sub _test_union {
418     my ($self, $rect) = (@_);
419     my ($x, $y, $w, $h);
420
421     $x = $self->x < $rect->x ? $self->x : $rect->x;  # MIN
422     $y = $self->y < $rect->y ? $self->y : $rect->y;  # MIN
423     
424     $w = ($self->x + $self->w) > ($rect->x + $rect->w)
425        ? ($self->x + $self->w) - $x
426        : ($rect->x + $rect->w) - $x
427        ;  # MAX
428        
429     $h = ($self->y + $self->h) > ($rect->y + $rect->h)
430        ? ($self->y + $self->h) - $y
431        : ($rect->y + $rect->h) - $y
432        ;  # MAX
433
434     return ($x, $y, $w, $h);
435 }
436
437 sub union {
438     my ($self, $rect) = (@_);
439     
440     unless ($rect->isa('SDL::Rect')) {
441         croak "must receive an SDL::Rect-based object";
442     }
443     
444     my ($x, $y, $w, $h) = _test_union($self, $rect);
445     return $self->new($x, $y, $w, $h);
446 }
447
448 sub union_ip {
449     my ($self, $rect) = (@_);
450     
451     unless ($rect->isa('SDL::Rect')) {
452         croak "must receive an SDL::Rect-based object";
453     }
454     
455     my ($x, $y, $w, $h) = _test_union($self, $rect);
456     
457     $self->x($x);
458     $self->y($y);
459     $self->w($w);
460     $self->y($h);
461     
462     return;
463 }
464
465 sub _test_unionall {
466     my ($self, $rects) = (@_);
467     
468     # initial values for union rect
469     my $left   = $self->x;
470     my $top    = $self->y;
471     my $right  = $self->x + $self->w;
472     my $bottom = $self->y + $self->h;
473     
474     foreach my $rect (@{$rects}) {
475         unless ($rect->isa('SDL::Rect')) {
476             # TODO: better error message, maybe saying which item 
477             # is the bad one (by list position)
478             croak "must receive an array reference of SDL::Rect-based objects";
479         }
480
481         $left   = $rect->x if $rect->x < $left; # MIN
482         $top    = $rect->y if $rect->y < $top; # MIN
483         $right  = ($rect->x + $rect->w) if ($rect->x + $rect->w) > $right;  # MAX
484         $bottom = ($rect->y + $rect->h) if ($rect->y + $rect->h) > $bottom; # MAX 
485     }
486     
487     return ($left, $top, $right - $left, $bottom - $top);
488 }
489
490 sub unionall {
491     my ($self, $rects) = (@_);
492     
493     unless (defined $rects and ref $rects eq 'ARRAY') {
494         croak "must receive an array reference of SDL::Rect-based objects";
495     }
496
497     my ($x, $y, $w, $h) = _test_unionall($self, $rects);
498     
499     return $self->new($x, $y, $w, $h);
500 }
501
502 sub unionall_ip {
503     my ($self, $rects) = (@_);
504     
505     unless (defined $rects and ref $rects eq 'ARRAY') {
506         croak "must receive an array reference of SDL::Rect-based objects";
507     }
508
509     my ($x, $y, $w, $h) = _test_unionall($self, $rects);
510     
511     $self->x($x);
512     $self->y($y);
513     $self->w($w);
514     $self->h($h);
515     
516     return;
517 }
518
519 sub _check_fit {
520     my ($self, $rect) = (@_);
521     
522     my $x_ratio = $self->w / $rect->w;
523     my $y_ratio = $self->h / $rect->h;
524     my $max_ratio = ($x_ratio > $y_ratio) ? $x_ratio : $y_ratio;
525
526     my $w = int ($self->w / $max_ratio);
527     my $h = int ($self->h / $max_ratio);
528
529     my $x = $rect->x + int (($rect->w - $w) / 2);
530     my $y = $rect->y + int (($rect->h - $h) / 2);
531     
532     return ($x, $y, $w, $h);
533 }
534
535 sub fit {
536     my ($self, $rect) = (@_);
537     
538     unless ($rect->isa('SDL::Rect')) {
539         croak "must receive an SDL::Rect-based object";
540     }
541
542     my ($x, $y, $w, $h) = _check_fit($self, $rect);
543     
544     return $self->new ($x, $y, $w, $h);
545 }
546
547 sub fit_ip {
548     my ($self, $rect) = (@_);
549     
550     unless ($rect->isa('SDL::Rect')) {
551         croak "must receive an SDL::Rect-based object";
552     }
553
554     my ($x, $y, $w, $h) = _check_fit($self, $rect);
555     
556     $self->x($x);
557     $self->y($y);
558     $self->w($w);
559     $self->h($h);
560     
561     return;
562 }
563
564 sub normalize {
565     my $self = shift;
566     
567     if ($self->w < 0) {
568         $self->x($self->x + $self->w);
569         $self->w(-$self->w);
570     }
571     
572     if ($self->h < 0) {
573         $self->y( $self->y + $self->h);
574         $self->h(-$self->h);
575     }
576     return;
577 }
578
579 sub contains {
580     my ($self, $rect) = (@_);
581     
582     unless ($rect->isa('SDL::Rect')) {
583         croak "must receive an SDL::Rect-based object";
584     }
585     
586     my $contained = ($self->x <= $rect->x) 
587                  && ($self->y <= $rect->y) 
588                  && ($self->x + $self->w >= $rect->x + $rect->w) 
589                  && ($self->y + $self->h >= $rect->y + $rect->h) 
590                  && ($self->x + $self->w > $rect->x) 
591                  && ($self->y + $self->h > $rect->y)
592                  ;
593                  
594     return $contained;
595 }
596
597 sub collidepoint {
598     my ($self, $x, $y) = (@_);
599
600     unless (defined $x and defined $y) {
601         croak "must receive (x,y) as arguments";
602     }
603     
604     my $inside = $x >= $self->x 
605               && $x < $self->x + $self->w 
606               && $y >= $self->y 
607               && $y < $self->y + $self->h
608               ;
609
610     return $inside;
611 }
612
613 sub _do_rects_intersect {
614     my ($rect_A, $rect_B) = (@_);
615     
616     return (
617                ($rect_A->x >= $rect_B->x && $rect_A->x < $rect_B->x + $rect_B->w)  
618             || ($rect_B->x >= $rect_A->x && $rect_B->x < $rect_A->x + $rect_A->w)
619            ) 
620            &&
621            (
622                ($rect_A->y >= $rect_B->y && $rect_A->y < $rect_B->y + $rect_B->h)
623             || ($rect_B->y >= $rect_A->y && $rect_B->y < $rect_A->y + $rect_A->h)
624            )
625            ;
626 }
627
628
629 sub colliderect {
630     my ($self, $rect) = (@_);
631
632     unless ($rect->isa('SDL::Rect')) {
633         croak "must receive an SDL::Rect-based object";
634     }
635     
636     return _do_rects_intersect($self, $rect);
637 }
638
639 sub collidelist {
640     my ($self, $rects) = (@_);
641
642     unless (defined $rects and ref $rects eq 'ARRAY') {
643         croak "must receive an array reference of SDL::Rect-based objects";
644     }
645
646     for(my $i = 0; $i < @{$rects}; $i++) {
647         if ( _do_rects_intersect($self, $rects->[$i]) ) {
648             return $i;
649         }
650     }
651     return;
652 }
653
654 sub collidelistall {
655     my ($self, $rects) = (@_);
656
657     unless (defined $rects and ref $rects eq 'ARRAY') {
658         croak "must receive an array reference of SDL::Rect-based objects";
659     }
660
661     my @collisions = ();
662     for(my $i = 0; $i < @{$rects}; $i++) {
663         if ( _do_rects_intersect($self, $rects->[$i]) ) {
664             push @collisions, $i;
665         }
666     }
667     return \@collisions;
668 }
669
670 sub collidehash {
671     my ($self, $rects) = (@_);
672
673     unless (defined $rects and ref $rects eq 'HASH') {
674         croak "must receive an hash reference of SDL::Rect-based objects";
675     }
676     
677     while ( my ($key, $value) = each %{$rects} ) {
678         unless ($value->isa('SDL::Rect')) {
679             croak "hash element of key '$key' is not an SDL::Rect-based object";
680         }
681         
682         if ( _do_rects_intersect($self, $value) ) {
683             return ($key, $value);
684         }
685     }
686     return (undef, undef);
687 }
688
689 sub collidehashall {
690     my ($self, $rects) = (@_);
691
692     unless (defined $rects and ref $rects eq 'HASH') {
693         croak "must receive an hash reference of SDL::Rect-based objects";
694     }
695     
696     my %collisions = ();
697     while ( my ($key, $value) = each %{$rects} ) {
698         unless ($value->isa('SDL::Rect')) {
699             croak "hash element of key '$key' is not an SDL::Rect-based object";
700         }
701         
702         if ( _do_rects_intersect($self, $value) ) {
703             $collisions{$key} = $value;
704         }
705     }
706     return \%collisions;
707 }
708
709
710 42;
711 __END__
712
713 =head1 NAME
714
715 SDL::Game::Rect - SDL::Game object for storing and manipulating rectangular coordinates
716
717 =head1 SYNOPSIS
718
719
720 =head1 DESCRIPTION
721
722 C<< SDL::Game::Rect >> object are used to store and manipulate rectangular areas. Rect objects are created from a combination of left (or x), top (or y), width (or w) and height (or h) values, just like raw C<< SDL::Rect objects >>.
723
724 All C<< SDL::Game::Rect >> methods that change either position or size of a Rect return B<a new copy> of the Rect with the affected changes. The original Rect is B<not> modified. If you wish to modify the current Rect object, you can use the equivalent "in-place" methods that do not return but instead affects the original Rect. These "in-place" methods are denoted with the "ip" suffix. Note that changing a Rect's attribute is I<always> an in-place operation.
725
726
727 =head2 ATTRIBUTES
728
729 All Rect attributes are acessors, meaning you can get them by name, and set them by passing a value:
730
731    $rect->left(15);
732    $rect->left;       # 15
733
734 The Rect object has several attributes which can be used to resize, move and align the Rect.
735
736
737 =over 4
738
739 =item * width, w - gets/sets object's width
740
741 =item * height, h - gets/sets object's height
742
743 =item * left, x - moves the object left position to match the given coordinate
744
745 =item * top, y  - moves the object top position to match the given coordinate
746
747 =item * bottom - moves the object bottom position to match the given coordinate
748
749 =item * right - moves the object right position to match the given coordinate
750
751 =item * centerx - moves the object's horizontal center to match the given coordinate
752
753 =item * centery - moves the object's vertical center to match the given coordinate
754
755 =back
756
757 Some of the attributes above can be fetched or set in pairs:
758
759   $rect->topleft(10, 15);   # top is now 10, left is now 15
760
761   my ($width, $height) = $rect->size;
762
763
764 =over 4
765
766 =item * size - gets/sets object's size (width, height)
767
768 =item * topleft - gets/sets object's top and left positions
769
770 =item * midleft - gets/sets object's vertical center and left positions
771
772 =item * bottomleft - gets/sets object's bottom and left positions
773
774 =item * center - gets/sets object's center (horizontal(x), vertical(y))
775
776 =item * topright - gets/sets object's top and right positions
777
778 =item * midright - gets/sets object's vertical center and right positions
779
780 =item * bottomright - gets/sets object's bottom and right positions
781
782 =item * midtop - gets/sets object's horizontal center and top positions
783
784 =item * midbottom - gets/sets object's horizontal center and bottom positions
785
786 =back
787
788
789 =head2 METHODS 
790
791 Methods denoted as receiving Rect objects can receive either C<<SDL::Game::Rect>> or raw C<<SDL::Rect>> objects.
792
793 =head3 new ($left, $top, $width, $height)
794
795 Returns a new Rect object with the given coordinates. If any value is omitted (by passing undef), 0 is used instead.
796
797 =head3 copy
798
799 =head3 duplicate
800
801 Returns a new Rect object having the same position and size as the original
802
803 =head3 move(x, y)
804
805 Returns a new Rect that is moved by the given offset. The x and y arguments can be any integer value, positive or negative.
806
807 =head3 move_ip(x, y)
808
809 Same as C<<move>> above, but moves the current Rect in place and returns nothing.
810
811 =head3 inflate(x, y)
812
813 Grows or shrinks the rectangle. Returns a new Rect with the size changed by the given offset. The rectangle remains centered around its current center. Negative values will return a shrinked rectangle instead.
814
815 =head3 inflate_ip(x, y)
816
817 Same as C<<inflate>> above, but grows/shrinks the current Rect in place and returns nothing.
818
819 =head3 clamp($rect)
820
821 Returns a new Rect moved to be completely inside the Rect object passed as an argument. If the current Rect is too large to fit inside the passed Rect, it is centered inside it, but its size is not changed.
822
823 =head3 clamp_ip($rect)
824
825 Same as C<<clamp>> above, but moves the current Rect in place and returns nothing.
826
827 =head3 clip($rect)
828
829 Returns a new Rect with the intersection between the two Rect objects, that is, returns a new Rect cropped to be completely inside the Rect object passed as an argument. If the two rectangles do not overlap to begin with, a Rect with 0 size is returned, in the original Rect's (x,y) coordinates.
830
831 =head3 clip_ip($rect)
832
833 Same as C<<clip>> above, but crops the current Rect in place and returns nothing. As the original method, the Rect becomes zero-sized if the two rectangles do not overlap to begin with, retaining its (x, y) coordinates.
834
835 =head3 union($rect)
836
837 Returns a new rectangle that completely covers the area of the current Rect and the one passed as an argument. There may be area inside the new Rect that is not covered by the originals.
838
839 =head3 union_ip($rect)
840
841 Same as C<<union>> above, but resizes the current Rect in place and returns nothing.
842
843 =head3 unionall( [$rect1, $rect2, ...] )
844
845 Returns the union of one rectangle with a sequence of many rectangles, passed as an ARRAY REF.
846
847 =head3 unionall_ip( [$rect1, $rect2, ...] )
848
849 Same as C<<unionall>> above, but resizes the current Rect in place and returns nothing.
850
851 =head3 fit($rect)
852
853 Returns a new Rect moved and resized to fit the Rect object passed as an argument. The aspect ratio of the original Rect is preserved, so the new rectangle may be smaller than the target in either width or height. 
854
855 =head3 fit_ip($rect)
856
857 Same as C<<fit>> above, but moves/resizes the current Rect in place and returns nothing.
858
859 =head3 normalize
860
861 Corrects negative sizes, flipping width/height of the Rect if they have a negative size. No repositioning is made so the rectangle will remain in the same place, but the negative sides will be swapped. This method returns nothing.
862
863 =head3 contains($rect)
864
865 Returns true (non-zero) when the argument is completely inside the Rect. Otherwise returns undef.
866
867 =head3 collidepoint(x, y)
868
869 Returns true (non-zero) if the given point is inside the Rect, otherwise returns undef. A point along the right or bottom edge is not considered to be inside the rectangle.
870
871 =head3 colliderect($rect)
872
873 Returns true (non-zero) if any portion of either rectangles overlap (except for the top+bottom or left+right edges).
874
875 =head3 collidelist( [$rect1, $rect2, ...] )
876
877 Test whether the rectangle collides with any in a sequence of rectangles, passed as an ARRAY REF. The index of the first collision found is returned. Returns undef if no collisions are found.
878
879 =head3 collidelistall( [$rect1, $rect2, ...] )
880
881 Returns an ARRAY REF of all the indices that contain rectangles that collide with the Rect. If no intersecting rectangles are found, an empty list ref is returned. 
882
883 =head3 collidehash( {key1 => $rect1, key2 => $rect2, ...} )
884
885 Receives a HASH REF and returns the a (key, value) list with the key and value of the first hash item that collides with the Rect. If no collisions are found, returns (undef, undef).
886
887 =head3 collidehashall( {key1 => $rect1, key2 => $rect2, ...} )
888
889 Returns a HASH REF of all the key and value pairs that intersect with the Rect. If no collisions are found an empty hash ref is returned. 
890
891
892 =head1 AUTHOR
893
894 Breno G. de Oliveira, C<< <garu at cpan.org> >>
895
896 =head1 BUGS
897
898 Please report any bugs or feature requests to the bug tracker. I will be notified, and then you'll automatically be notified of progress on your bug as we make changes.
899
900
901 =head1 SUPPORT
902
903 You can find documentation for this module with the perldoc command.
904
905     perldoc SDL::Game::Rect
906
907
908 =head1 ACKNOWLEDGEMENTS
909
910 Many thanks to all SDL_Perl contributors, and to the authors of pygame.rect, in which this particular module is heavily based.
911
912 =head1 COPYRIGHT & LICENSE
913
914 Copyright 2009 Breno G. de Oliveira, all rights reserved.
915
916 This program is free software; you can redistribute it and/or modify it
917 under the same terms as Perl itself.
918
919
920 =head1 SEE ALSO
921
922 perl, L<SDL>, L<SDL::Rect>, L<SDL::Game>