1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Copyright (C) 2017-2023 David Thompson dthompson2@worcester.edu
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
A copy of the license is also available from the Free Software
Foundation Web site at http://www.gnu.org/licenses/fdl.html.
* Chickadee: (chickadee). Game programming toolkit for Guile.
The document was typeset with
http://www.texinfo.org/ (GNU Texinfo).
-->
<!-- Created by GNU Texinfo 6.7, http://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The Game Loop (The Chickadee Game Toolkit)</title>
<meta name="description" content="The Game Loop (The Chickadee Game Toolkit)" />
<meta name="keywords" content="The Game Loop (The Chickadee Game Toolkit)" />
<meta name="resource-type" content="document" />
<meta name="distribution" content="global" />
<meta name="Generator" content="makeinfo" />
<link href="index.html" rel="start" title="Top" />
<link href="Index.html" rel="index" title="Index" />
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents" />
<link href="Kernel.html" rel="up" title="Kernel" />
<link href="Input-Devices.html" rel="next" title="Input Devices" />
<link href="Kernel.html" rel="prev" title="Kernel" />
<style type="text/css">
<!--
a.summary-letter {text-decoration: none}
blockquote.indentedblock {margin-right: 0em}
div.display {margin-left: 3.2em}
div.example {margin-left: 3.2em}
div.lisp {margin-left: 3.2em}
kbd {font-style: oblique}
pre.display {font-family: inherit}
pre.format {font-family: inherit}
pre.menu-comment {font-family: serif}
pre.menu-preformatted {font-family: serif}
span.nolinebreak {white-space: nowrap}
span.roman {font-family: initial; font-weight: normal}
span.sansserif {font-family: sans-serif; font-weight: normal}
ul.no-bullet {list-style: none}
@media (min-width: 1140px) {
body {
margin-left: 14rem;
margin-right: 4rem;
max-width: 52rem;
}
}
@media (min-width: 800px) and (max-width: 1140px) {
body {
margin-left: 6rem;
margin-right: 4rem;
max-width: 52rem;
}
}
@media (max-width: 800px) {
body {
margin: 1rem;
}
}
-->
</style>
<link rel="stylesheet" type="text/css" href="https://dthompson.us/css/dthompson.css" />
</head>
<body lang="en">
<span id="The-Game-Loop"></span><div class="header">
<p>
Next: <a href="Input-Devices.html" accesskey="n" rel="next">Input Devices</a>, Up: <a href="Kernel.html" accesskey="u" rel="up">Kernel</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Index.html" title="Index" rel="index">Index</a>]</p>
</div>
<hr />
<span id="The-Game-Loop-1"></span><h4 class="subsection">5.1.1 The Game Loop</h4>
<p>At the very core of Chickadee there is an event loop. This loop, or
“kernel”, is responsible for ensuring that the game is updated at
the desired interval, handling input devices, rendering the current
state of the game world, and handling errors if they occur. The
kernel implements what is known as a “fixed timestep” game loop,
meaning that the game simulation will be advanced by a fixed interval
of time and will never vary from frame to frame, unlike some other
styles of game loops. The appropriately named <code>run-game</code> and
<code>abort-game</code> procedures are the entry and exit points to the
Chickadee game loop.
</p>
<p>If you are using <code>chickadee play</code> to launch your game, then
calling <code>run-game</code> is already taken care of for you.
</p>
<dl>
<dt id="index-run_002dgame">Procedure: <strong>run-game</strong> <em>[#:window-title "Chickadee!"] [#:window-width 640] [#:window-height 480] [#:window-fullscreen? <code>#f</code>] [#:window-resizable? <code>#f</code>] [#:update-hz 60] [#:clear-color] [#:load] [#:update] [#:draw] [#:quit] [#:key-press] [#:key-release] [#:text-input] [#:mouse-press] [#:mouse-release] [#:mouse-move] [#:controller-add] [#:controller-remove] [#:controller-press] [#:controller-release] [#:controller-move] [#:window-keyboard-enter] [#:window-keyboard-leave] [#:window-mouse-enter] [#:window-mouse-leave] [#:window-show] [#:window-hide] [#:window-minimize] [#:window-maximize] [#:window-move] [#:window-resize] [#:error]</em></dt>
<dd>
<p>Run the Chickadee game loop.
</p>
<p>A new graphical window will be opened with <var>window-width</var> x
<var>window-height</var> as its dimensions, <var>window-title</var> as its
title, and in fullscreen mode if <var>window-fullscreen?</var> is
<code>#t</code>. If <var>window-resizable?</var> is <code>#t</code> then the window
can be resized by the user. The screen color will be set to
<var>clear-color</var>, or a pleasant light blue, by default.
</p>
<ul>
<li> <var>load</var>: Called with zero arguments when the game window has opened
but before the game loop has started. Can be used to perform
initialization that requires an open window and OpenGL context such as
loading textures.
</li><li> <var>update</var>: Called <var>update-hz</var> times per second with one
argument: The amount of time to advance the game simulation.
</li><li> <var>draw</var>: Called each time a frame should be rendered with a single
argument known as the <code>alpha</code> value. See the documentation for
<code>run-game*</code> for an explanation of this value.
</li><li> <var>quit</var>: Called with zero arguments when the user tries to close
the game window. The default behavior is to exit the game.
</li><li> <var>key-press</var>: Called with four arguments when a key is pressed on
the keyboard:
<ol>
<li> <var>key</var>: The symbolic name of the key that was pressed. For
example: <code>backspace</code>.
</li><li> <var>modifiers</var>: A list of the symbolic names of modifier keys that
were being held down when the key was pressed. Possible values
include <code>ctrl</code>, <code>alt</code>, and <code>shift</code>.
</li><li> <var>repeat?</var>: <code>#t</code> if this is a repeated press of the same key.
</li></ol>
</li><li> <var>key-release</var>: Called with three arguments when a key is released
on the keyboard:
<ol>
<li> <var>key</var>: The symbolic name of the key that was released.
</li><li> <var>modifiers</var>: A list of the symbolic names of modifier keys that
were being held down when the key was released.
</li></ol>
</li><li> <var>text-input</var>: Called with a single argument, a string of text,
when printable text is typed on the keyboard.
</li><li> <var>mouse-press</var>: Called with four arguments when a mouse button is
pressed:
<ol>
<li> <var>button</var>: The symbolic name of the button that was pressed, such
as <code>left</code>, <code>middle</code>, or <code>right</code>.
</li><li> <var>clicks</var>: The number of times the button has been clicked in a row.
</li><li> <var>x</var>: The x coordinate of the mouse cursor.
</li><li> <var>y</var>: The y coordinate of the mouse cursor.
</li></ol>
</li><li> <var>mouse-release</var>: Called with three arguments when a mouse button
is released:
<ol>
<li> <var>button</var>: The symbolic name of the button that was released.
</li><li> <var>x</var>: The x coordinate of the mouse cursor.
</li><li> <var>y</var>: The y coordinate of the mouse cursor.
</li></ol>
</li><li> <var>mouse-move</var>: Called with five arguments when the mouse is moved:
<ol>
<li> <var>x</var>: The x coordinate of the mouse cursor.
</li><li> <var>y</var>: The y coordinate of the mouse cursor.
</li><li> <var>dx</var>: The amount the mouse has moved along the x axis since the
last mouse move event.
</li><li> <var>dy</var>: The amount the mouse has moved along the y axis since the
last mouse move event.
</li><li> <var>buttons</var>: A list of the buttons that were pressed down when the
mouse was moved.
</li></ol>
</li><li> <var>mouse-wheel</var>: Called with two arguments when the mouse wheel is
scrolled:
<ol>
<li> <var>x</var>: The scroll amount along the X axis.
</li><li> <var>y</var>: The scroll amount along the Y axis.
</li></ol>
</li><li> <var>controller-add</var>: Called with a single argument, an SDL game
controller object, when a game controller is connected.
</li><li> <var>controller-remove</var>: Called with a single argument, an SDL game
controller object, when a game controller is disconnected.
</li><li> <var>controller-press</var>: Called with two arguments when a button on a
game controller is pressed:
<ol>
<li> <var>controller</var>: The controller that triggered the event.
</li><li> <var>button</var>: The symbolic name of the button that was pressed.
Possible buttons are:
<ul>
<li> <code>a</code>
</li><li> <code>b</code>
</li><li> <code>x</code>
</li><li> <code>y</code>
</li><li> <code>back</code>
</li><li> <code>guide</code>
</li><li> <code>start</code>
</li><li> <code>left-stick</code>
</li><li> <code>right-stick</code>
</li><li> <code>left-shoulder</code>
</li><li> <code>right-shoulder</code>
</li><li> <code>dpad-up</code>
</li><li> <code>dpad-down</code>
</li><li> <code>dpad-left</code>
</li><li> <code>dpad-right</code>
</li></ul>
</li></ol>
</li><li> <var>controller-release</var>: Called with two arguments when a button on a
game controller is released:
<ol>
<li> <var>controller</var>: The controller that triggered the event.
</li><li> <var>button</var>: The symbolic name of the button that was released.
</li></ol>
</li><li> <var>controller-move</var>: Called with three arguments when an analog
stick or trigger on a game controller is moved:
<ol>
<li> <var>controller</var>: The controller that triggered the event.
</li><li> <var>axis</var>: The symbolic name of the axis that was moved. Possible
values are:
<ul>
<li> <code>left-x</code>
</li><li> <code>left-y</code>
</li><li> <code>right-x</code>
</li><li> <code>right-y</code>
</li><li> <code>trigger-left</code>
</li><li> <code>trigger-right</code>
</li></ul>
</li></ol>
</li><li> <var>window-keyboard-enter</var>: Called with zero arguments when the
window gains keyboard focus.
</li><li> <var>window-keyboard-leave</var>: Called with zero arguments when the
window loses keyboard focus.
</li><li> <var>window-mouse-enter</var>: Called with zero arguments when the window
gains mouse focus.
</li><li> <var>window-mouse-leave</var>: Called with zero arguments when the window
loses mouse focus.
</li><li> <var>window-show</var>: Called with zero arguments when the window is
shown after having been hidden.
</li><li> <var>window-hide</var>: Called with zero arguments when the window is
hidden.
</li><li> <var>window-minimize</var>: Called with zero arguments when the window is
minimized.
</li><li> <var>window-maximize</var>: Called with zero arguments when the window is
maximized.
</li><li> <var>window-move</var>: Called with two arguments when the window is moved
within the desktop environment.
<ol>
<li> <var>x</var>: The x coordinate of the top-left corner of the window, in
pixels.
</li><li> <var>y</var>: The y coordinate of the top-left corner of the window, in
pixels.
</li></ol>
<p>Desktop environments use the top-left corner as the origin rather than
the bottom-left like Chickadee does, hence the discrepancy here.
</p>
</li><li> <var>window-resize</var>: Called with zero arguments when the window is
resized.
<ol>
<li> <var>width</var>: The new width in pixels.
</li><li> <var>height</var>: The new height in pixels.
</li></ol>
</li><li> <var>error</var>: Called with two arguments when an error occurs:
<ol>
<li> <var>exception</var>: The exception object.
</li><li> <var>stack</var>: The call stack at the point of the exception.
</li></ol>
<p>If no error handler is specified, exceptions will simply be re-raised.
</p>
</li></ul>
</dd></dl>
<p>To stop the game loop, simply call <code>abort-game</code>.
</p>
<dl>
<dt id="index-abort_002dgame">Procedure: <strong>abort-game</strong></dt>
<dd><p>Stop the currently running Chickadee game loop.
</p></dd></dl>
<p>The above explanation of the game loop was partially a lie. It’s true
that there is a game loop at the center of Chickadee, but
<code>run-game</code> is not it’s true entry point. There exists an even
lower level procedure, <code>run-game*</code>, in the <code>(chickadee
game-loop)</code> module that <code>run-game</code> uses under the hood.
</p>
<p>On its own, <code>run-game*</code> does not do very much at all. In order
to actually respond to input events, update game state, or render
output, the developer must provide an engine. <code>run-game</code> is such
an engine, and it’s likely all a developer will need. However, what
if a developer wanted to use all of the useful Chickadee features to
make a terminal roguelike game instead? Chickadee doesn’t come with a
terminal rendering engine, but the developer could write one without
having to write their own core game loop.
</p>
<dl>
<dt id="index-run_002dgame_002a">Procedure: <strong>run-game*</strong> <em>[#:init] [#:update] [#:render] [#:time] [#:error] [#:update-hz 60]</em></dt>
<dd>
<p>Start the game loop. This procedure will not return until
<code>abort-game</code> is called.
</p>
<p>The core game loop is generic and requires four additional procedures
to operate:
</p>
<ul>
<li> <var>init</var>: Called just before game loop is started. Use it to
perform game initialization.
</li><li> <var>update</var>: Called <var>update-hz</var> times per second to advance the
game simulation. This procedure is called with a single argument: The
amount of time that has passed since the last update, in milliseconds.
</li><li> <var>render</var>: Called each iteration of the loop to render the game to
the desired output device. This procedure is called with a single
argument: A value in the range [0, 1] which represents how much time
has past since the last game state update relative to the upcoming
game state update, as a percentage. Because the game state is updated
independent of rendering, it is often the case that rendering is
occuring between two updates. If the game is rendered as it was
during the last update, a strange side-effect will occur that makes
animation appear rough or “choppy”. To counter this, the
<var>alpha</var> value can be used to perfrom a linear interpolation of a
moving object between its current position and its previous position.
This odd trick has the pleasing result of making the animation look
smooth again, but requires keeping track of previous state.
</li><li> <var>time</var>: Called to get the current time in seconds. This procedure
is called with no arguments.
</li><li> <var>error</var>: Called when an error from the <var>update</var> or
<var>render</var> procedures reaches the game loop. This procedure is
called with three arguments: The call stack, the error key, and the
error arguments. If no error handler is provided, the default
behavior is to simply re-throw the error.
</li></ul>
</dd></dl>
<dl>
<dt id="index-elapsed_002dtime">Procedure: <strong>elapsed-time</strong></dt>
<dd><p>Return the current value of the system timer in seconds.
</p></dd></dl>
<hr />
<div class="header">
<p>
Next: <a href="Input-Devices.html" accesskey="n" rel="next">Input Devices</a>, Up: <a href="Kernel.html" accesskey="u" rel="up">Kernel</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Index.html" title="Index" rel="index">Index</a>]</p>
</div>
</body>
</html>
|