File Coverage

blib/lib/Collision/2D/Entity/Point.pm
Criterion Covered Total %
statement 68 71 95.7
branch 39 46 84.7
condition 66 82 80.4
subroutine 8 9 88.8
pod 0 2 0.0
total 181 210 86.1


line stmt bran cond sub pod time code
1             package Collision::2D::Entity::Point;
2 7     7   36 use strict;
  7         14  
  7         225  
3 7     7   93 use warnings;
  7         12  
  7         698  
4              
5             require DynaLoader;
6             our @ISA = qw(DynaLoader Collision::2D::Entity);
7             bootstrap Collision::2D::Entity::Point;
8              
9              
10 184     184   496 sub _p{3} #meh priority
11 7     7   38 use overload '""' => sub{'point'};
  7     164   13  
  7         82  
  164         387  
12 1     1 0 383 sub typename{'point'}
13              
14             sub new{
15 163     163 0 571 my ($package, %params) = @_;
16 163   100     3073 my $self = __PACKAGE__->_new (
      100        
      100        
      100        
      100        
      100        
      100        
      100        
17             $params{x} || 0,
18             $params{y} || 0,
19             $params{xv} || 0,
20             $params{yv} || 0,
21             $params{relative_x} || 0,
22             $params{relative_y} || 0,
23             $params{relative_xv} || 0,
24             $params{relative_yv} || 0,
25             );
26 163         593 return $self;
27             }
28              
29             #I daresay, 2 points mayn't collide
30             sub _collide_point{
31 0     0   0 return;
32             }
33              
34              
35             #Here, $self is assumed to be normalized.
36              
37             sub _collide_rect{
38 78     78   157 my ($self, $rect, %params) = @_;
39             #if we start inside rect, return the null collision, so to speak.
40             #if ($rect->contains_point($self)){
41             # return $self->null_collision($rect)
42             #}
43             #this line segment is path of point during this interval
44 78         192 my $x1 = $self->relative_x;
45 78         253 my $x2 = $x1 + ($self->relative_xv * $params{interval});
46 78         151 my $y1 = $self->relative_y;
47 78         210 my $y2 = $y1 + ($self->relative_yv * $params{interval});
48 78         173 my $w = $rect->w;
49 78         141 my $h = $rect->h;
50            
51             #if it contains point at t=0, relatively...
52 78 50 100     535 if ( $x1>0 and $x1<$w
      100        
      66        
53             and $y1>0 and $y1<$h){
54 0         0 return $self->null_collision($rect);
55             }
56             else{
57             #start outside box, so return if no relative movement
58 78 50 33     512 return unless $params{interval} and ($self->relative_x or $self->relative_y);
      33        
59             }
60 78 100       212 unless ($self->relative_xv){ #no horizontal movement. Don't worry about inverting, it's easy.
61 25 50 33     170 return unless ($x1 > 0 and $x1 < $w);
62 25         33 my $t;
63 25 100 66     164 if ($y1 < 0 and $y2 > 0){
    50 33        
64 22         43 $t = -$y1 / $self->relative_yv;
65             } elsif ($y1 > $h and $y2 < $h){
66 3         12 $t = ($y1-$h) / -$self->relative_yv;
67             }else {
68             return
69 0         0 }
70 25         87 return Collision::2D::Collision->new(
71             time => $t,
72             axis => 'y',
73             ent1 => $self,
74             ent2 => $rect,
75             );
76             }
77            
78             #now see if point starts and ends on one of 4 sides of this rect.
79             #probably worth it because most things don't collide with each other every frame
80 53 100 100     143 if ($x1 > $w and $x2 > $w ){
81             return
82 1         4 }
83 52 100 100     201 if ($x1 < 0 and $x2 < 0){
84             return
85 5         17 }
86 47 100 100     155 if ($y1 > $h and $y2 > $h ){
87             return
88 1         5 }
89 46 100 100     129 if ($y1 < 0 and $y2 < 0){
90             return
91 1         8 }
92            
93             #not that simple. either it enters rect, or passes by a corner. check each rect line segment.
94 45         55 my ($best_time, $best_axis);
95 45 50       121 if ($self->relative_xv){
96 45 100 66     231 if ($x1 < 0 and $x2 > 0){ # horizontally pass rect's left side
    100 66        
97 29         128 my $t = (-$x1) / $self->relative_xv;
98 29         116 my $y_at_t = $y1 + ($t * $self->relative_yv);
99 29 100 100     128 if ($y_at_t < $h and $y_at_t > 0) {
100 12         16 $best_time = $t;
101 12         23 $best_axis = 'x';
102             }
103             }
104             elsif ($x1 > $w and $x2 < $w){ #horizontally pass rect's right side
105 6         24 my $t = ($x1 - $w) / -$self->relative_xv;
106 6         74 my $y_at_t = $y1 + ($t * $self->relative_yv);
107 6 100 100     36 if ($y_at_t < $h and $y_at_t > 0) {
108 4         8 $best_time = $t;
109 4         7 $best_axis = 'x';
110             }
111             }
112             }
113 45 100       124 if ($self->relative_yv){
114 39 100 100     194 if ($y1 < 0 and $y2 > 0){ #vertically pass rect's lower side
    100 66        
115 10         26 my $t = (-$y1) / $self->relative_yv;
116 10 50 33     27 if (!defined($best_time) or $t < $best_time){
117 10         22 my $x_at_t = $x1 + ($t * $self->relative_xv);
118 10 100 100     55 if ($x_at_t < $w and $x_at_t > 0) {
119 4         7 $best_time = $t;
120 4         6 $best_axis = 'y';
121             }
122             }
123             }
124             elsif ($y1 > $h and $y2 < $h){ #vertically pass rect's upper side
125 17         51 my $t = ($y1 - $h) / -$self->relative_yv;
126 17 50 66     120 if (!defined($best_time) or $t < $best_time){
127 17         53 my $x_at_t = $x1 + ($t * $self->relative_xv);
128 17 100 100     80 if ($x_at_t < $w and $x_at_t > 0) {
129 8         14 $best_time = $t;
130 8         13 $best_axis = 'y';
131             }
132             }
133             }
134             }
135 45 100       139 return unless $best_axis;
136 28         119 return Collision::2D::Collision->new(
137             time => $best_time,
138             axis => $best_axis,
139             ent1 => $self,
140             ent2 => $rect,
141             );
142             }
143              
144             2
145              
146             __END__
147             =head1 NAME
148              
149             Collision::2D::Entity::Rect - A Point entity.
150              
151             =head1 DESCRIPTION
152              
153             This is a point entity.
154             Attributes (x, y) are the location of this point. See L<Collision::2D::Entity>.
155              
156             Points can not collide with other points. Use a very small circle instead.
157              
158             =head1 ATTRIBUTES
159              
160             Anything in L<Collision::2D::Entity>.
161              
162             =head1 METHODS
163              
164             Anything in L<Collision::2D::Entity>.
165              
166             =head2 collide
167              
168             See L<< Collision::2D::Entity->collide|Collision::2D::Entity/collide >>
169              
170             print 'boom' if $point->collide($rect);
171             print 'zing' if $point->collide($circle);
172             print 'yotz' if $point->collide($grid);
173            
174             =head2 intersect
175              
176             See L<< Collision::2D::Entity->intersect|Collision::2D::Entity/intersect >>
177              
178             print 'bam' if $point->intersect($rect);
179             # etc..