File Coverage

blib/lib/SDLx/Controller.pm
Criterion Covered Total %
statement 144 177 81.3
branch 23 42 54.7
condition 5 13 38.4
subroutine 33 42 78.5
pod 0 23 0.0
total 205 297 69.0


line stmt bran cond sub pod time code
1             package SDLx::Controller;
2 6     6   502 use strict;
  6         8  
  6         169  
3 6     6   20 use warnings;
  6         7  
  6         127  
4 6     6   20 use Carp;
  6         7  
  6         219  
5 6     6   22 use Time::HiRes;
  6         7  
  6         44  
6 6     6   380 use SDL;
  6         7  
  6         280  
7 6     6   244 use SDL::Event;
  6         6  
  6         3159  
8 6     6   271 use SDL::Events;
  6         7  
  6         9390  
9 6     6   32 use SDL::Video;
  6         9  
  6         810  
10 6     6   1820 use SDLx::Controller::Interface;
  6         11  
  6         179  
11 6     6   1428 use SDLx::Controller::State;
  6         13  
  6         253  
12 6     6   29 use Scalar::Util 'refaddr';
  6         9  
  6         6975  
13              
14             # inside out, so this can work as the superclass of another
15             # SDL::Surface subclass
16             my %_dt;
17             my %_min_t;
18             my %_current_time;
19             my %_stop;
20             my %_event;
21             my %_event_handlers;
22             my %_move_handlers;
23             my %_show_handlers;
24             my %_sleep_cycle;
25             my %_eoq;
26             my %_paused;
27              
28             sub new {
29 6     6 0 1705 my ($self, %args) = @_;
30 6 100       19 if(ref $self) {
31 3         6 bless $self, ref $self;
32             }
33             else {
34 3         5 my $a;
35 3         9 $self = bless \$a, $self;
36             }
37              
38 6         19 my $ref = refaddr $self;
39              
40 6 100       24 $_dt{ $ref } = defined $args{dt} ? $args{dt} : 0.1;
41 6 100       16 $_min_t{ $ref } = defined $args{min_t} ? $args{min_t} : 1 / 60;
42             # $_current_time{ $ref } = $args{current_time} || 0; #no point
43 6         10 $_stop{ $ref } = $args{stop};
44 6   33     89 $_event{ $ref } = $args{event} || SDL::Event->new();
45 6   50     30 $_event_handlers{ $ref } = $args{event_handlers} || [];
46 6   50     24 $_move_handlers{ $ref } = $args{move_handlers} || [];
47 6   50     28 $_show_handlers{ $ref } = $args{show_handlers} || [];
48 6         10 $_sleep_cycle{ $ref } = $args{delay};
49 6   50     45 $_eoq{$ref} = $args{exit_on_quit} || $args{eoq} || 0;
50             # $_paused{ $ref } = $args{paused}; #read only
51              
52 6         16 return $self;
53             }
54              
55              
56             sub delay {
57 0     0 0 0 my $self = shift;
58 0         0 my $delay = shift;
59 0         0 my $ref = refaddr $self;
60            
61 0 0       0 $_sleep_cycle{ $ref } = $delay if $delay;
62 0         0 return $self;
63             }
64              
65             sub DESTROY {
66 1     1   5 my $self = shift;
67 1         3 my $ref = refaddr $self;
68              
69 1         3 delete $_dt{ $ref};
70 1         2 delete $_min_t{ $ref};
71 1         1 delete $_current_time{ $ref};
72 1         2 delete $_stop{ $ref};
73 1         3 delete $_event{ $ref};
74 1         2 delete $_event_handlers{ $ref};
75 1         2 delete $_move_handlers{ $ref};
76 1         2 delete $_show_handlers{ $ref};
77 1         1 delete $_sleep_cycle { $ref };
78 1         2 delete $_eoq{$ref};
79 1         3 delete $_paused{$ref};
80             }
81              
82             sub run {
83 2     2 0 13 my ($self) = @_;
84 2         7 my $ref = refaddr $self;
85 2         6 my $dt = $_dt{ $ref };
86 2         4 my $min_t = $_min_t{ $ref };
87 2         4 my $t = 0.0;
88              
89             #Allows us to do stop and run
90 2         3 $_stop{ $ref } = 0;
91              
92 2         11 $_current_time{ $ref } = Time::HiRes::time;
93 2         8 while ( !$_stop{ $ref } ) {
94 2292514         1881634 $self->_event($ref);
95              
96 2292514         2075125 my $new_time = Time::HiRes::time;
97 2292514         1547200 my $delta_time = $new_time - $_current_time{ $ref };
98 2292514 100       3872626 next if $delta_time < $min_t;
99 32         49 $_current_time{ $ref} = $new_time;
100 32         58 my $delta_copy = $delta_time;
101              
102 32         96 while ( $delta_copy > $dt ) {
103 150         304 $self->_move( $ref, 1, $t ); #a full move
104 150         269824 $delta_copy -= $dt;
105 150         398 $t += $dt;
106             }
107 32         62 my $step = $delta_copy / $dt;
108 32         88 $self->_move( $ref, $step, $t ); #a partial move
109 32         54029 $t += $dt * $step;
110              
111 32         117 $self->_show( $ref, $delta_time );
112              
113 32         44014 $dt = $_dt{ $ref}; #these can change
114 32         69 $min_t = $_min_t{ $ref}; #during the cycle
115 32 100       400443 SDL::delay( $_sleep_cycle{ $ref } ) if $_sleep_cycle{ $ref };
116             }
117              
118             }
119              
120             sub exit_on_quit {
121 12     12 0 15 my ($self, $value) = @_;
122              
123 12         21 my $ref = refaddr $self;
124 12 100       25 if (defined $value) {
125 2         3 $_eoq{$ref} = $value;
126             }
127              
128 12         35 return $_eoq{$ref};
129             }
130             *eoq = \&exit_on_quit; # alias
131              
132             sub pause {
133 0     0 0 0 my ($self, $callback) = @_;
134 0         0 my $ref = refaddr $self;
135 0   0 0   0 $callback ||= sub {1};
  0         0  
136 0         0 my $event = SDL::Event->new();
137 0         0 $_paused{ $ref} = 1;
138 0         0 while(1) {
139 0 0       0 SDL::Events::wait_event($event) or Carp::confess("pause failed waiting for an event");
140 0 0       0 if($callback->($event, $self)) {
141 0         0 $_current_time{ $ref} = Time::HiRes::time; #so run doesn't catch up with the time paused
142 0         0 last;
143             }
144             }
145 0         0 delete $_paused{ $ref};
146             }
147              
148             sub _event {
149 2292514     2292514   1447250 my ($self, $ref) = @_;
150 2292514         3744553 while ( SDL::Events::poll_event( $_event{ $ref} ) ) {
151 1 50       9 $self->_exit_on_quit( $_event{ $ref} ) if $_eoq{$ref};
152 1         2 foreach my $event_handler ( @{ $_event_handlers{ $ref} } ) {
  1         5  
153 1 50       4 next unless $event_handler;
154 1         5 $event_handler->( $_event{ $ref}, $self );
155             }
156             }
157             }
158              
159             sub _move {
160 182     182   239 my ($self, $ref, $move_portion, $t) = @_;
161 182         160 foreach my $move_handler ( @{ $_move_handlers{ $ref} } ) {
  182         472  
162 362 50       76558 next unless $move_handler;
163 362         769 $move_handler->( $move_portion, $self, $t );
164             }
165             }
166              
167             sub _show {
168 32     32   67 my ($self, $ref, $delta_ticks) = @_;
169 32         53 foreach my $show_handler ( @{ $_show_handlers{ $ref} } ) {
  32         104  
170 62 50       10509 next unless $show_handler;
171 62         165 $show_handler->( $delta_ticks, $self );
172             }
173             }
174              
175 5     5 0 1754 sub stop { $_stop{ refaddr $_[0] } = 1 }
176              
177             sub _add_handler {
178 13     13   14 my ( $arr_ref, $handler ) = @_;
179 13         10 push @{$arr_ref}, $handler;
  13         14  
180 13         11 return $#{$arr_ref};
  13         29  
181             }
182              
183             sub add_move_handler {
184 5     5 0 354 my $ref = refaddr $_[0];
185 5         16 return _add_handler( $_move_handlers{ $ref}, $_[1] );
186             }
187              
188             sub add_event_handler {
189 3     3 0 353 my $ref = refaddr $_[0];
190 3 50       27 Carp::confess 'SDLx::App or a Display (SDL::Video::get_video_mode) must be made'
191             unless SDL::Video::get_video_surface();
192 3         18 return _add_handler( $_event_handlers{ $ref}, $_[1] );
193             }
194              
195             sub add_show_handler {
196 5     5 0 411 my $ref = refaddr $_[0];
197 5         12 return _add_handler( $_show_handlers{ $ref}, $_[1] );
198             }
199              
200             sub _remove_handler {
201 8     8   8 my ( $arr_ref, $id ) = @_;
202 8 100       23 if ( ref $id ) {
    50          
203 6         13 ($id) = grep {
204 3         7 $id eq $arr_ref->[$_]
205 3         6 } 0..$#{$arr_ref};
206              
207 3 50       7 if ( !defined $id ) {
208 0         0 Carp::cluck("$id is not currently a handler of this type");
209 0         0 return;
210             }
211             }
212             elsif(!defined $arr_ref->[$id]) {
213 0         0 Carp::cluck("$id is not currently a handler of this type");
214 0         0 return;
215             }
216 8         23 return delete( $arr_ref->[$id] );
217             }
218              
219             sub remove_move_handler {
220 3     3 0 15 return _remove_handler( $_move_handlers{ refaddr $_[0] }, $_[1] );
221             }
222              
223             sub remove_event_handler {
224 2     2 0 12 return _remove_handler( $_event_handlers{ refaddr $_[0] }, $_[1] );
225             }
226              
227             sub remove_show_handler {
228 3     3 0 15 return _remove_handler( $_show_handlers{ refaddr $_[0] }, $_[1] );
229             }
230              
231             sub remove_all_handlers {
232 0     0 0 0 $_[0]->remove_all_move_handlers;
233 0         0 $_[0]->remove_all_event_handlers;
234 0         0 $_[0]->remove_all_show_handlers;
235             }
236              
237             sub remove_all_move_handlers {
238 0     0 0 0 $_move_handlers{ refaddr $_[0] } = [];
239             }
240              
241             sub remove_all_event_handlers {
242 1     1 0 6 $_event_handlers{ refaddr $_[0] } = [];
243             }
244              
245             sub remove_all_show_handlers {
246 0     0 0 0 $_show_handlers{ refaddr $_[0] } = [];
247             }
248              
249 5     5 0 927 sub move_handlers { $_move_handlers{ refaddr $_[0] } }
250 6     6 0 665 sub event_handlers { $_event_handlers{ refaddr $_[0] } }
251 5     5 0 660 sub show_handlers { $_show_handlers{ refaddr $_[0] } }
252              
253             sub dt {
254 4     4 0 310 my ($self, $arg) = @_;
255 4         14 my $ref = refaddr $self;
256 4 50       12 $_dt{ $ref} = $arg if defined $arg;
257              
258 4         38 $_dt{ $ref};
259             }
260              
261             sub min_t {
262 2     2 0 3 my ($self, $arg) = @_;
263 2         5 my $ref = refaddr $self;
264 2 50       6 $_min_t{ $ref} = $arg if defined $arg;
265              
266 2         8 $_min_t{ $ref};
267             }
268              
269             sub current_time {
270 0     0 0   my ($self, $arg) = @_;
271 0           my $ref = refaddr $self;
272 0 0         $_current_time{ $ref} = $arg if defined $arg;
273              
274 0           $_current_time{ $ref};
275             }
276              
277             sub paused {
278 0     0 0   $_paused{ refaddr $_[0]};
279             }
280              
281             sub _exit_on_quit {
282 0     0     my ($self, $event) = @_;
283              
284 0 0         $self->stop() if $event->type == SDL_QUIT;
285             }
286              
287             1;
288              
289             __END__