File Coverage

blib/lib/Game/Collisions.pm
Criterion Covered Total %
statement 61 67 91.0
branch 11 12 91.6
condition 5 6 83.3
subroutine 12 13 92.3
pod 6 7 85.7
total 95 105 90.4


line stmt bran cond sub pod time code
1             # Copyright (c) 2018 Timm Murray
2             # All rights reserved.
3             #
4             # Redistribution and use in source and binary forms, with or without
5             # modification, are permitted provided that the following conditions are met:
6             #
7             # * Redistributions of source code must retain the above copyright notice,
8             # this list of conditions and the following disclaimer.
9             # * Redistributions in binary form must reproduce the above copyright
10             # notice, this list of conditions and the following disclaimer in the
11             # documentation and/or other materials provided with the distribution.
12             #
13             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23             # POSSIBILITY OF SUCH DAMAGE.
24             package Game::Collisions;
25             $Game::Collisions::VERSION = '0.4';
26 21     21   1490158 use v5.14;
  21         256  
27 21     21   113 use warnings;
  21         37  
  21         649  
28 21     21   129 use List::Util ();
  21         52  
  21         420  
29              
30 21     21   8774 use Game::Collisions::AABB;
  21         45  
  21         13643  
31              
32             # ABSTRACT: Fast, pure Perl collision 2D detection
33              
34              
35             sub new
36             {
37 10     10 1 853 my ($class) = @_;
38 10         43 my $self = {
39             root_aabb => undef,
40             all_aabbs => {},
41             };
42 10         25 bless $self => $class;
43              
44              
45 10         29 return $self;
46             }
47              
48              
49             sub make_aabb
50             {
51 36     36 1 1154 my ($self, $args) = @_;
52 36         122 my $aabb = Game::Collisions::AABB->new( $args );
53 36         91 $self->_add_aabb( $aabb );
54 36         90 return $aabb;
55             }
56              
57             sub get_collisions
58             {
59 5     5 1 734 my ($self) = @_;
60 5         80 my @aabbs_to_check = values %{ $self->{all_aabbs} };
  5         41  
61 5         9 my @collisions;
62              
63 5         13 foreach my $aabb (@aabbs_to_check) {
64 20         36 push @collisions => $self->get_collisions_for_aabb( $aabb );
65             }
66              
67 5         22 return @collisions;
68             }
69              
70             sub get_collisions_for_aabb
71             {
72 20     20 1 30 my ($self, $aabb) = @_;
73 20 50       43 return () if ! defined $self->{root_aabb};
74 20         22 my @collisions;
75              
76 20         28 my @nodes_to_check = ($self->{root_aabb});
77 20         39 while( @nodes_to_check ) {
78 95         107 my $check_node = shift @nodes_to_check;
79              
80 95 100       158 if( $check_node->is_branch_node ) {
81 63         101 my $left_node = $check_node->left_node;
82 63         89 my $right_node = $check_node->right_node;
83              
84 63 100 66     132 if( defined $left_node && $left_node->does_collide( $aabb ) ) {
85 53         63 push @nodes_to_check, $left_node;
86             }
87 63 100 100     211 if( defined $right_node && $right_node->does_collide( $aabb ) ) {
88 22         50 push @nodes_to_check, $right_node;
89             }
90             }
91             else {
92             # We already know it collided, since it wouldn't be added
93             # to @nodes_to_check otherwise.
94 32         97 push @collisions, [ $aabb, $check_node ];
95             }
96             }
97              
98 20         45 return @collisions;
99             }
100              
101             sub get_collisions_for_aabb_bruteforce
102             {
103 0     0 1 0 my ($self, $aabb) = @_;
104 0         0 my @aabbs = values %{ $self->{all_aabbs} };
  0         0  
105              
106 0         0 my @collisions = grep { $_->does_collide( $aabb ) } @aabbs;
  0         0  
107 0         0 return @collisions;
108             }
109              
110             sub rebalance_tree
111             {
112 1     1 1 6 my ($self) = @_;
113 1         34 my @aabbs = values %{ $self->{all_aabbs} };
  1         8  
114 1         4 $self->{all_aabbs} = {};
115              
116 1         4 my $new_root = $self->_new_meta_aabb({
117             x => 0,
118             y => 0,
119             length => 1,
120             height => 1,
121             });
122 1         2 $self->{root_aabb} = $new_root;
123 1         3 $self->_add_aabb( $_ ) for @aabbs;
124              
125 1         7 return;
126             }
127              
128             sub root
129             {
130 1     1 0 6 my ($self) = @_;
131 1         7 return $self->{root_aabb};
132             }
133              
134              
135             sub _add_aabb
136             {
137 40     40   61 my ($self, $new_node) = @_;
138              
139 40 100       143 if(! defined $self->{root_aabb} ) {
140 10         26 $self->{root_aabb} = $new_node;
141             }
142             else {
143 30         79 my $new_root = $self->{root_aabb}->insert_new_aabb( $new_node );
144 30 100       84 $self->{root_aabb} = $new_root if defined $new_root;
145             }
146              
147 40         153 $self->{all_aabbs}{"$new_node"} = $new_node;
148 40         67 return;
149             }
150              
151             sub _new_meta_aabb
152             {
153 1     1   3 my ($self, $args) = @_;
154 1         3 my $aabb = Game::Collisions::AABB->new( $args );
155 1         2 return $aabb;
156             }
157              
158              
159             1;
160             __END__