Commit | Line | Data |
807ae0cd |
1 | <div class="pod"> |
2 | <!-- INDEX START --> |
3 | <h3 id="TOP">Index</h3> |
4 | |
5 | <ul><li><a href="#NAME">NAME</a></li> |
39c8ca1e |
6 | <li><a href="#CATEGORY">CATEGORY</a></li> |
807ae0cd |
7 | <li><a href="#SYNOPSIS">SYNOPSIS</a> |
8 | <ul><li><a href="#DESCRIPTION">DESCRIPTION</a></li> |
9 | </ul> |
10 | </li> |
11 | <li><a href="#METHODS">METHODS</a> |
12 | <ul><li><a href="#new">new</a></li> |
807ae0cd |
13 | <li><a href="#run">run</a></li> |
7a14b086 |
14 | <li><a href="#stop">stop</a></li> |
15 | <li><a href="#pause">pause</a></li> |
fcf60e89 |
16 | <li><a href="#paused">paused</a></li> |
807ae0cd |
17 | <li><a href="#add_event_handler">add_event_handler</a></li> |
18 | <li><a href="#add_move_handler">add_move_handler</a></li> |
19 | <li><a href="#add_show_handler">add_show_handler</a></li> |
807ae0cd |
20 | <li><a href="#remove_move_handler_index">remove_move_handler( $index )</a></li> |
21 | <li><a href="#remove_event_handler_index">remove_event_handler( $index )</a></li> |
22 | <li><a href="#remove_show_handler_index">remove_show_handler( $index )</a></li> |
23 | <li><a href="#remove_all_move_handlers">remove_all_move_handlers</a></li> |
24 | <li><a href="#remove_all_event_handlers">remove_all_event_handlers</a></li> |
25 | <li><a href="#remove_all_show_handlers">remove_all_show_handlers</a></li> |
26 | <li><a href="#remove_all_handlers">remove_all_handlers</a></li> |
7a14b086 |
27 | <li><a href="#dt">dt</a></li> |
28 | <li><a href="#min_t">min_t</a></li> |
29 | <li><a href="#current_time">current_time</a></li> |
807ae0cd |
30 | </ul> |
31 | </li> |
32 | <li><a href="#AUTHORS">AUTHORS</a> |
33 | <ul><li><a href="#ACKNOWLEGDEMENTS">ACKNOWLEGDEMENTS</a> |
34 | </li> |
35 | </ul> |
36 | </li> |
37 | </ul><hr /> |
38 | <!-- INDEX END --> |
39 | |
40 | <h1 id="NAME">NAME</h1><p><a href="#TOP" class="toplink">Top</a></p> |
41 | <div id="NAME_CONTENT"> |
7a14b086 |
42 | <p>SDLx::Controller - Handles the loops for events, movement and rendering</p> |
807ae0cd |
43 | |
44 | </div> |
39c8ca1e |
45 | <h1 id="CATEGORY">CATEGORY</h1><p><a href="#TOP" class="toplink">Top</a></p> |
46 | <div id="CATEGORY_CONTENT"> |
47 | <p>Extension, Controller</p> |
48 | |
49 | </div> |
807ae0cd |
50 | <h1 id="SYNOPSIS">SYNOPSIS</h1><p><a href="#TOP" class="toplink">Top</a></p> |
51 | <div id="SYNOPSIS_CONTENT"> |
4769fd12 |
52 | <pre> use SDLx::Controller; |
807ae0cd |
53 | |
4769fd12 |
54 | # create our controller object |
55 | my $app = SDLx::Controller->new; |
807ae0cd |
56 | |
4769fd12 |
57 | # we could also do: |
58 | my $app = SDLx::App->new; |
59 | # because App is also a controller |
807ae0cd |
60 | |
4769fd12 |
61 | # register some callbacks |
62 | $app->add_event_handler( \&on_event ); |
63 | $app->add_move_handler( \&on_move ); |
64 | $app->add_show_handler( \&on_show ); |
807ae0cd |
65 | |
4769fd12 |
66 | # run our game loop |
67 | $app->run; |
807ae0cd |
68 | |
69 | </pre> |
70 | |
71 | </div> |
72 | <h2 id="DESCRIPTION">DESCRIPTION</h2> |
73 | <div id="DESCRIPTION_CONTENT"> |
4769fd12 |
74 | <p>The core of an SDL application/game is the main loop, where you handle events |
807ae0cd |
75 | and display your elements on the screen until something signals the end of |
76 | the program. This usually goes in the form of:</p> |
77 | <pre> while (1) { |
78 | ... |
79 | } |
80 | |
81 | </pre> |
82 | <p>The problem most developers face, besides the repetitive work, is to ensure |
83 | the screen update is independent of the frame rate. Otherwise, your game will |
84 | run at different speeds on different machines and this is never good (old |
85 | MS-DOS games, anyone?).</p> |
86 | <p>One way to circumveint this is by capping the frame rate so it's the same no |
87 | matter what, but this is not the right way to do it as it penalizes better |
88 | hardware.</p> |
89 | <p>This module provides an industry-proven standard for frame independent |
7a14b086 |
90 | movement. It calls the movement handlers based on time (hi-res seconds) rather |
807ae0cd |
91 | than frame rate. You can add/remove handlers and control your main loop with |
92 | ease.</p> |
93 | |
94 | </div> |
95 | <h1 id="METHODS">METHODS</h1><p><a href="#TOP" class="toplink">Top</a></p> |
96 | <div id="METHODS_CONTENT"> |
97 | |
98 | </div> |
99 | <h2 id="new">new</h2> |
100 | <div id="new_CONTENT"> |
7a14b086 |
101 | <pre> SDLx::Controller->new( |
102 | dt => 0.5, |
103 | min_t => 0, |
104 | event => $event_object, |
105 | ); |
807ae0cd |
106 | |
7a14b086 |
107 | </pre> |
108 | <p>The <code>dt</code> parameter specifies the length, in seconds, of a full movement step, and defaults to 0.1. |
109 | The <code>dt</code> can be anything and the game can still look the same. |
110 | It is only when you change the <code>dt</code> without changing all the things in the movement step that are being multiplied by the first move argument that it will make a difference. |
111 | If you lower the <code>dt</code>, everything will move faster than it did with it set higher, and vice-versa. |
112 | This is useful to add slo-mo and fast-forward features to the game, all you would have to do is change the <code>dt</code>.</p> |
113 | <p><code>min_t</code> specifies the minimum time, in seconds, that has to accumulate before any move or show handlers are called, and defaults to 1 / 60. |
4769fd12 |
114 | Having the <code>min_t</code> at 1 / 60 ensures that the controller can update the screen at a maximum of 60 times per second. |
7a14b086 |
115 | A "V-Sync" such as this is necessary to prevent video "tear", which occurs when the app is updating faster than the monitor can display. |
4769fd12 |
116 | Setting it to 0, as seen above, will let the app run as fast as it possibly can.</p> |
fcf60e89 |
117 | <p><code>delay</code> specifies a loop delay in millisecs to place on the controller loop. <strong>NOTE:</strong> Picking a good delay based on the needs can help reduce CPU load and pressure.</p> |
4769fd12 |
118 | <p><code>event</code> is a SDL::Event object that events going to the event callbacks are polled in to. It defaults to <code>SDL::Event->new()</code>.</p> |
7a14b086 |
119 | <p>All parameters are optional.</p> |
807ae0cd |
120 | <p>Returns the new object.</p> |
121 | |
122 | </div> |
123 | <h2 id="run">run</h2> |
124 | <div id="run_CONTENT"> |
125 | <p>After creating and setting up your handlers (see below), call this method to |
7a14b086 |
126 | activate the main loop. The main loop will run until <code>stop</code> is called.</p> |
807ae0cd |
127 | <p>All hooked functions will be called during the main loop, in this order:</p> |
128 | <dl> |
129 | <dt>1. Events</dt> |
130 | <dt>2. Movements</dt> |
131 | <dt>3. Displaying</dt> |
132 | </dl> |
7a14b086 |
133 | <p>Please refer to each handler below for information on received arguments. |
134 | Note that the second argument every callback recieves is the <code>SDLx::Controller</code> object.</p> |
135 | |
136 | </div> |
137 | <h2 id="stop">stop</h2> |
138 | <div id="stop_CONTENT"> |
139 | <p>Returns from the <code>run</code> loop.</p> |
140 | |
141 | </div> |
142 | <h2 id="pause">pause</h2> |
143 | <div id="pause_CONTENT"> |
144 | <p>Attempts to pause the application with a call to <code>SDL::Events::wait_event</code>. See <a href="SDL-Events.html">SDL::Events</a>.</p> |
145 | <p>Takes 1 argument which is a callback. The application waits for the next event with <code>wait_event</code>. |
146 | When one is recieved, it is passed to the callback as the first argument, along with the <code>SDLx::Controller</code> object as the second argument. |
147 | If the callback then returns a true value, <code>pause</code> will return. |
4769fd12 |
148 | If the callback returns a false value, <code>pause</code> will repeat the process.</p> |
7a14b086 |
149 | <p>This can be used to easily implement a pause when the app loses focus:</p> |
4769fd12 |
150 | <pre> sub window { |
151 | my ($e, $app) = @_; |
152 | if($e->type == SDL_QUIT) { |
153 | $app->stop; |
154 | # quit handling is here so that the app |
155 | # can be stopped while paused |
156 | } |
157 | elsif($e->type == SDL_ACTIVEEVENT) { |
7a14b086 |
158 | if($e->active_state & SDL_APPINPUTFOCUS) { |
159 | if($e->active_gain) { |
160 | return 1; |
161 | } |
162 | else { |
4769fd12 |
163 | $app->pause(\&window); |
7a14b086 |
164 | # recursive, but only once since the window |
165 | # can't lose focus again without gaining is first |
166 | } |
167 | } |
168 | } |
169 | return 0; |
170 | } |
171 | |
172 | </pre> |
173 | <p>Note: if you implement your own pause function, remember to update <code>current_time</code> to the current time when the application unpauses. |
174 | This should be done with <code>Time::HiRes::time</code>. |
175 | Otherwise, time will accumulate while the application is paused, and many movement steps will be called all at once when it unpauses.</p> |
176 | <p>Note 2: a pause will be potentially dangerous to the <code>run</code> cycle (even if you implement your own) unless called by an <code>event</code> callback.</p> |
807ae0cd |
177 | |
178 | </div> |
fcf60e89 |
179 | <h2 id="paused">paused</h2> |
180 | <div id="paused_CONTENT"> |
181 | <p>Returns 1 if the app is paused, undef otherwise. |
182 | This is only useful when used within code that will be run by <code>pause</code>:</p> |
183 | <pre> sub pause { |
184 | # press P to toggle pause |
185 | |
186 | my ($e, $app) = @_; |
187 | if($e->type == SDL_QUIT) { |
188 | $app->stop; |
189 | # quit handling is here so that the app |
190 | # can be stopped while paused |
191 | } |
192 | elsif($e->type == SDL_KEYDOWN) { |
193 | if($e->key_sym == SDLK_P) { |
194 | # We're paused, so end pause |
195 | return 1 if $app->paused; |
196 | |
197 | # We're not paused, so pause |
198 | $app->pause(\&pause); |
199 | } |
200 | } |
201 | return 0; |
202 | } |
203 | |
204 | |
205 | |
206 | |
207 | </pre> |
208 | |
209 | </div> |
807ae0cd |
210 | <h2 id="add_event_handler">add_event_handler</h2> |
211 | <div id="add_event_handler_CONTENT"> |
212 | <p>Register a callback to handle events. You can add as many subs as you need. |
213 | Whenever a SDL::Event occurs, all registered callbacks will be triggered in |
214 | order. Returns the order queue number of the added callback.</p> |
7a14b086 |
215 | <p>The first argument passed to registered callbacks is the <a href="SDL-Event.html">SDL::Event</a> object. |
216 | The second is the <code>SDLx::Controller</code> object.</p> |
217 | <pre> sub stop { |
218 | my ($event, $app) = @_; |
219 | if($event->type == SDL_QUIT) { |
4769fd12 |
220 | $app->stop; |
7a14b086 |
221 | } |
222 | } |
4769fd12 |
223 | $app->add_event_handler(\&stop); |
807ae0cd |
224 | |
7a14b086 |
225 | </pre> |
807ae0cd |
226 | |
227 | </div> |
228 | <h2 id="add_move_handler">add_move_handler</h2> |
229 | <div id="add_move_handler_CONTENT"> |
230 | <p>Register a callback to update your objects. You can add as many subs as |
231 | you need. Returns the order queue number of the added callback.</p> |
7a14b086 |
232 | <p>All registered callbacks will be triggered in order for as many <code>dt</code> as have happened between calls, |
233 | and once more for any remaining time less than <code>dt</code>. |
234 | The first argument passed to the callbacks is the portion of the step, which will be 1 for a full step, and less than 1 for a partial step. |
235 | Movement values should be multiplied by this value. |
236 | The full steps correspond to the amount of <code>dt</code> passed between calls, and the partial step corresponds to the call with the remaining time less than <code>dt</code>. |
4769fd12 |
237 | The argument can be 0 if no time has passed since the last cycle. If you need to protect against this, set a <code>min_t</code>, or put a <code>return unless $_[0]</code> at the start of every move handler.</p> |
7a14b086 |
238 | <p>The second argument passed to the callbacks is the <code>SDLx::Controller</code> object. |
239 | The third is the total amount of time passed since the call of <code>run</code>.</p> |
240 | <p>You should use these handlers to update your in-game objects, check collisions, etc. |
807ae0cd |
241 | so you can check and/or update it as necessary.</p> |
7a14b086 |
242 | <pre> sub move_ball { |
243 | my ($step, $app, $t) = @_; |
244 | $ball->move_x( $ball->x_vel * $step ); |
245 | $ball->move_y( $ball->y_vel * $step ); |
246 | } |
807ae0cd |
247 | |
7a14b086 |
248 | </pre> |
807ae0cd |
249 | |
250 | </div> |
251 | <h2 id="add_show_handler">add_show_handler</h2> |
252 | <div id="add_show_handler_CONTENT"> |
253 | <p>Register a callback to render objects. You can add as many subs as you need. |
7a14b086 |
254 | Returns the order queue number of the added callback. |
255 | All registered callbacks will be triggered in order, once per run of the <code>run</code> loop.</p> |
4769fd12 |
256 | <p>The first argument passed is the time, in seconds, since the previous call. |
7a14b086 |
257 | The second is the <code>SDLx::Controller</code> object.</p> |
258 | <pre> sub show_ball { |
259 | my ($delta, $app) = @_; |
260 | $app->draw_rect( |
261 | [ $ball->x, $ball->y, $ball->size, $ball->size ], |
262 | $ball->colour |
263 | ); |
264 | } |
807ae0cd |
265 | |
7a14b086 |
266 | </pre> |
807ae0cd |
267 | |
268 | </div> |
269 | <h2 id="remove_move_handler_index">remove_move_handler( $index )</h2> |
270 | <div id="remove_move_handler_index_CONTENT"> |
271 | |
272 | </div> |
273 | <h2 id="remove_event_handler_index">remove_event_handler( $index )</h2> |
274 | <div id="remove_event_handler_index_CONTENT"> |
275 | |
276 | </div> |
277 | <h2 id="remove_show_handler_index">remove_show_handler( $index )</h2> |
278 | <div id="remove_show_handler_index_CONTENT"> |
279 | <p>Removes the handler with the given index from the respective calling queue.</p> |
505f308d |
280 | <p>You can also pass a coderef. |
281 | The first coderef in the handler list that this matches will be removed.</p> |
807ae0cd |
282 | <p>Returns the removed handler.</p> |
283 | |
284 | </div> |
285 | <h2 id="remove_all_move_handlers">remove_all_move_handlers</h2> |
286 | <div id="remove_all_move_handlers_CONTENT"> |
287 | |
288 | </div> |
289 | <h2 id="remove_all_event_handlers">remove_all_event_handlers</h2> |
290 | <div id="remove_all_event_handlers_CONTENT"> |
291 | |
292 | </div> |
293 | <h2 id="remove_all_show_handlers">remove_all_show_handlers</h2> |
294 | <div id="remove_all_show_handlers_CONTENT"> |
295 | <p>Removes all handlers from the respective calling queue.</p> |
296 | |
297 | </div> |
298 | <h2 id="remove_all_handlers">remove_all_handlers</h2> |
299 | <div id="remove_all_handlers_CONTENT"> |
300 | <p>Quick access to removing all handlers at once.</p> |
301 | |
807ae0cd |
302 | </div> |
7a14b086 |
303 | <h2 id="dt">dt</h2> |
304 | <div id="dt_CONTENT"> |
305 | |
306 | </div> |
307 | <h2 id="min_t">min_t</h2> |
308 | <div id="min_t_CONTENT"> |
309 | |
310 | </div> |
311 | <h2 id="current_time">current_time</h2> |
312 | <div id="current_time_CONTENT"> |
313 | <p>If an argument is passed, modifies the corresponding value to the argument. |
314 | <code>dt</code> and <code>min_t</code> will keep their old value until the beginning of the next <code>run</code> cycle.</p> |
315 | <p>Returns the corresponding value.</p> |
316 | |
317 | </div> |
807ae0cd |
318 | <h1 id="AUTHORS">AUTHORS</h1><p><a href="#TOP" class="toplink">Top</a></p> |
319 | <div id="AUTHORS_CONTENT"> |
1dbe1697 |
320 | <p>See <a href="/SDL.html#AUTHORS">/SDL.html#AUTHORS</a>.</p> |
807ae0cd |
321 | |
322 | </div> |
323 | <h2 id="ACKNOWLEGDEMENTS">ACKNOWLEGDEMENTS</h2> |
324 | <div id="ACKNOWLEGDEMENTS_CONTENT"> |
325 | <p>The idea and base for this module comes from Lazy Foo's <a href="http://www.lazyfoo.net/SDL_tutorials/lesson32/index.php">Frame Independent Movement</a> tutorial, |
326 | and Glenn Fiedler's <a href="http://gafferongames.com/game-physics/fix-your-timestep/">Fix Your Timestep</a> article on timing.</p> |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | |
337 | |
338 | </div> |
339 | </div> |