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