You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: files/en-us/games/anatomy/index.md
+63-52
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,7 @@ tags:
7
7
- Main Loop
8
8
- requestAnimationFrame
9
9
---
10
+
10
11
{{GamesSidebar}}
11
12
12
13
This article looks at the anatomy and workflow of the average video game from a technical point of view, in terms of how the main loop should run. It helps beginners to modern game development understand what is required when building a game and how web standards like JavaScript lend themselves as tools. Experienced game programmers who are new to web development could also benefit, too.
@@ -55,13 +56,14 @@ But do not immediately assume animations require frame-by-frame control. Simple
55
56
56
57
There are two obvious issues with our previous main loop: `main()` pollutes the `{{ domxref("window") }}` object (where all global variables are stored) and the example code did not leave us with a way to _stop_ the loop unless the whole tab is closed or refreshed. For the first issue, if you want the main loop to just run and you do not need easy (direct) access to it, you could create it as an Immediately-Invoked Function Expression (IIFE).
57
58
59
+
<!-- prettier-ignore-start -->
58
60
```js
59
61
/*
60
-
* Starting with the semicolon is in case whatever line of code above this example
61
-
* relied on automatic semicolon insertion (ASI). The browser could accidentally
62
-
* think this whole example continues from the previous line. The leading semicolon
63
-
* marks the beginning of our new line if the previous one was not empty or terminated.
64
-
*/
62
+
* Starting with the semicolon is in case whatever line of code above this example
63
+
* relied on automatic semicolon insertion (ASI). The browser could accidentally
64
+
* think this whole example continues from the previous line. The leading semicolon
65
+
* marks the beginning of our new line if the previous one was not empty or terminated.
66
+
*/
65
67
66
68
;(() => {
67
69
functionmain() {
@@ -73,22 +75,24 @@ There are two obvious issues with our previous main loop: `main()` pollutes the
73
75
main(); // Start the cycle
74
76
})();
75
77
```
78
+
<!-- prettier-ignore-end -->
76
79
77
80
When the browser comes across this IIFE, it will define your main loop and immediately queue it for the next frame. It will not be attached to any object and `main` (or `main()` for methods) will be a valid unused name in the rest of the application, free to be defined as something else.
78
81
79
82
> **Note:** In practice, it is more common to prevent the next `requestAnimationFrame()` with an if-statement, rather than calling `cancelAnimationFrame()`.
80
83
81
84
For the second issue, stopping the main loop, you will need to cancel the call to `main()` with `{{ domxref("window.cancelAnimationFrame()") }}`. You will need to pass `cancelAnimationFrame()` the ID token given by `requestAnimationFrame()` when it was last called. Let us assume that your game's functions and variables are built on a namespace that you called `MyGame`. Expanding our last example, the main loop would now look like:
82
85
86
+
<!-- prettier-ignore-start -->
83
87
```js
84
88
/*
85
-
* Starting with the semicolon is in case whatever line of code above this example
86
-
* relied on automatic semicolon insertion (ASI). The browser could accidentally
87
-
* think this whole example continues from the previous line. The leading semicolon
88
-
* marks the beginning of our new line if the previous one was not empty or terminated.
89
-
*
90
-
* Let us also assume that MyGame is previously defined.
91
-
*/
89
+
* Starting with the semicolon is in case whatever line of code above this example
90
+
* relied on automatic semicolon insertion (ASI). The browser could accidentally
91
+
* think this whole example continues from the previous line. The leading semicolon
92
+
* marks the beginning of our new line if the previous one was not empty or terminated.
93
+
*
94
+
* Let us also assume that MyGame is previously defined.
95
+
*/
92
96
93
97
;(() => {
94
98
functionmain() {
@@ -100,6 +104,7 @@ For the second issue, stopping the main loop, you will need to cancel the call t
100
104
main(); // Start the cycle
101
105
})();
102
106
```
107
+
<!-- prettier-ignore-end -->
103
108
104
109
We now have a variable declared in our `MyGame` namespace, which we call `stopMain`, that contains the ID returned from our main loop's most recent call to `requestAnimationFrame()`. At any point, we can stop the main loop by telling the browser to cancel the request that corresponds to our token.
Back to the topic of the main loop. You will often want to know when your main function was invoked. Because this is common, `window.requestAnimationFrame()` always provides a `DOMHighResTimeStamp` to callbacks as an argument when they are executed. This leads to another enhancement to our previous main loops.
136
141
142
+
<!-- prettier-ignore-start -->
137
143
```js
138
144
/*
139
-
* Starting with the semicolon is in case whatever line of code above this example
140
-
* relied on automatic semicolon insertion (ASI). The browser could accidentally
141
-
* think this whole example continues from the previous line. The leading semicolon
142
-
* marks the beginning of our new line if the previous one was not empty or terminated.
143
-
*
144
-
* Let us also assume that MyGame is previously defined.
145
-
*/
145
+
* Starting with the semicolon is in case whatever line of code above this example
146
+
* relied on automatic semicolon insertion (ASI). The browser could accidentally
147
+
* think this whole example continues from the previous line. The leading semicolon
148
+
* marks the beginning of our new line if the previous one was not empty or terminated.
149
+
*
150
+
* Let us also assume that MyGame is previously defined.
151
+
*/
146
152
147
153
;(() => {
148
154
functionmain(tFrame) {
@@ -155,6 +161,7 @@ Back to the topic of the main loop. You will often want to know when your main f
155
161
main(); // Start the cycle
156
162
})();
157
163
```
164
+
<!-- prettier-ignore-end -->
158
165
159
166
Several other optimizations are possible and it really depends on what your game attempts to accomplish. Your game genre will obviously make a difference but it could even be more subtle than that. You could draw every pixel individually on a canvas or you could layer DOM elements (including multiple WebGL canvases with transparent backgrounds if you want) into a complex hierarchy. Each of these paths will lead to different opportunities and constraints.
160
167
@@ -168,15 +175,16 @@ You will need to make hard decisions about your main loop: how to simulate the a
168
175
169
176
If your game can hit the maximum refresh rate of any hardware you support then your job is fairly easy. You can update, render, and then do nothing until VSync.
170
177
178
+
<!-- prettier-ignore-start -->
171
179
```js
172
180
/*
173
-
* Starting with the semicolon is in case whatever line of code above this example
174
-
* relied on automatic semicolon insertion (ASI). The browser could accidentally
175
-
* think this whole example continues from the previous line. The leading semicolon
176
-
* marks the beginning of our new line if the previous one was not empty or terminated.
177
-
*
178
-
* Let us also assume that MyGame is previously defined.
179
-
*/
181
+
* Starting with the semicolon is in case whatever line of code above this example
182
+
* relied on automatic semicolon insertion (ASI). The browser could accidentally
183
+
* think this whole example continues from the previous line. The leading semicolon
184
+
* marks the beginning of our new line if the previous one was not empty or terminated.
185
+
*
186
+
* Let us also assume that MyGame is previously defined.
187
+
*/
180
188
181
189
;(() => {
182
190
functionmain(tFrame) {
@@ -189,6 +197,7 @@ If your game can hit the maximum refresh rate of any hardware you support then y
189
197
main(); // Start the cycle
190
198
})();
191
199
```
200
+
<!-- prettier-ignore-end -->
192
201
193
202
If the maximum refresh rate cannot be reached, quality settings could be adjusted to stay under your time budget. The most famous example of this concept is the game from id Software, RAGE. This game removed control from the user in order to keep its calculation time at roughly 16ms (or roughly 60fps). If computation took too long then rendered resolution would decrease, textures and other assets would fail to load or draw, and so forth. This (non-web) case study made a few assumptions and tradeoffs:
194
203
@@ -229,34 +238,35 @@ A separate update and draw method could look like the following example. For the
229
238
230
239
> **Warning:** This example, specifically, is in need of technical review.
231
240
241
+
<!-- prettier-ignore-start -->
232
242
```js
233
243
/*
234
-
* Starting with the semicolon is in case whatever line of code above this example
235
-
* relied on automatic semicolon insertion (ASI). The browser could accidentally
236
-
* think this whole example continues from the previous line. The leading semicolon
237
-
* marks the beginning of our new line if the previous one was not empty or terminated.
238
-
*
239
-
* Let us also assume that MyGame is previously defined.
240
-
*
241
-
* MyGame.lastRender keeps track of the last provided requestAnimationFrame timestamp.
242
-
* MyGame.lastTick keeps track of the last update time. Always increments by tickLength.
243
-
* MyGame.tickLength is how frequently the game state updates. It is 20 Hz (50ms) here.
244
-
*
245
-
* timeSinceTick is the time between requestAnimationFrame callback and last update.
246
-
* numTicks is how many updates should have happened between these two rendered frames.
247
-
*
248
-
* render() is passed tFrame because it is assumed that the render method will calculate
249
-
* how long it has been since the most recently passed update tick for
250
-
* extrapolation (purely cosmetic for fast devices). It draws the scene.
251
-
*
252
-
* update() calculates the game state as of a given point in time. It should always
253
-
* increment by tickLength. It is the authority for game state. It is passed
254
-
* the DOMHighResTimeStamp for the time it represents (which, again, is always
255
-
* last update + MyGame.tickLength unless a pause feature is added, etc.)
256
-
*
257
-
* setInitialState() Performs whatever tasks are leftover before the main loop must run.
258
-
* It is just a generic example function that you might have added.
259
-
*/
244
+
* Starting with the semicolon is in case whatever line of code above this example
245
+
* relied on automatic semicolon insertion (ASI). The browser could accidentally
246
+
* think this whole example continues from the previous line. The leading semicolon
247
+
* marks the beginning of our new line if the previous one was not empty or terminated.
248
+
*
249
+
* Let us also assume that MyGame is previously defined.
250
+
*
251
+
* MyGame.lastRender keeps track of the last provided requestAnimationFrame timestamp.
252
+
* MyGame.lastTick keeps track of the last update time. Always increments by tickLength.
253
+
* MyGame.tickLength is how frequently the game state updates. It is 20 Hz (50ms) here.
254
+
*
255
+
* timeSinceTick is the time between requestAnimationFrame callback and last update.
256
+
* numTicks is how many updates should have happened between these two rendered frames.
257
+
*
258
+
* render() is passed tFrame because it is assumed that the render method will calculate
259
+
* how long it has been since the most recently passed update tick for
260
+
* extrapolation (purely cosmetic for fast devices). It draws the scene.
261
+
*
262
+
* update() calculates the game state as of a given point in time. It should always
263
+
* increment by tickLength. It is the authority for game state. It is passed
264
+
* the DOMHighResTimeStamp for the time it represents (which, again, is always
265
+
* last update + MyGame.tickLength unless a pause feature is added, etc.)
266
+
*
267
+
* setInitialState() Performs whatever tasks are leftover before the main loop must run.
268
+
* It is just a generic example function that you might have added.
269
+
*/
260
270
261
271
;(() => {
262
272
functionmain(tFrame) {
@@ -293,6 +303,7 @@ A separate update and draw method could look like the following example. For the
293
303
main(performance.now()); // Start the cycle
294
304
})();
295
305
```
306
+
<!-- prettier-ignore-end -->
296
307
297
308
Another alternative is to do certain things less often. If a portion of your update loop is difficult to compute but insensitive to time, you might consider scaling back its frequency and, ideally, spreading it out into chunks throughout that lengthened period. An implicit example of this was found over at The Artillery Blog for Artillery Games, where they [adjust their rate of garbage generation](https://web.archive.org/web/20161021030645/http://blog.artillery.com/2012/10/browser-garbage-collection-and-framerate.html) to optimize garbage collection. Obviously, cleaning up resources is not time sensitive (especially if tidying is more disruptive than the garbage itself).
Copy file name to clipboardExpand all lines: files/en-us/games/examples/index.md
+3-4
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,7 @@ tags:
7
7
- Games
8
8
- Web
9
9
---
10
+
10
11
{{GamesSidebar}}
11
12
12
13
This page lists a number of impressive web technology demos for you to get inspiration from, and generally have fun with. A testament to what can be done with JavaScript, WebGL, and related technologies. The first two sections list playable games, while the second is a catch-all area to list demos that aren't necessarily interactive/games.
@@ -52,10 +53,8 @@ This page lists a number of impressive web technology demos for you to get inspi
Copy file name to clipboardExpand all lines: files/en-us/games/index.md
+1
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,7 @@ tags:
10
10
- JavaScript Games
11
11
- Web
12
12
---
13
+
13
14
{{GamesSidebar}}
14
15
15
16
Gaming is one of the most popular computer activities. New technologies are constantly arriving to make it possible to develop better and more powerful games that can be run in any standards-compliant web browser.
Copy file name to clipboardExpand all lines: files/en-us/games/publishing_games/game_distribution/index.md
+1
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,7 @@ tags:
14
14
- Web Stores
15
15
- distribution
16
16
---
17
+
17
18
{{GamesSidebar}}
18
19
19
20
You've followed a [tutorial](/en-US/docs/Games/Tutorials/2D_Breakout_game_pure_JavaScript) or [two](/en-US/docs/Games/Tutorials/2D_breakout_game_Phaser) and created an HTML game — that's great! This article covers all you need to know about the ways in which you can distribute your newly created game into the wild. This includes hosting it yourself online, submitting it to open marketplaces, and submitting it to closed ones like Google Play or the iOS App Store.
Copy file name to clipboardExpand all lines: files/en-us/games/publishing_games/game_monetization/index.md
+1
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,7 @@ tags:
11
11
- iap
12
12
- licensing
13
13
---
14
+
14
15
{{GamesSidebar}}
15
16
16
17
When you've spent your time building a game, [distributing](/en-US/docs/Games/Publishing_games/Game_distribution) it and [promoting](/en-US/docs/Games/Publishing_games/Game_promotion) it you should consider earning some money out of it. If your work is a serious endeavour on the path to becoming an independent game developer able to make a living, read on and see what your options are. The technology is mature enough; now it's just about choosing the right approach.
Copy file name to clipboardExpand all lines: files/en-us/games/publishing_games/game_promotion/index.md
+2-1
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,7 @@ tags:
10
10
- blog
11
11
- competitions
12
12
---
13
+
13
14
{{GamesSidebar}}
14
15
15
16
Developing and publishing your game is not enough. You have to let the world know that you have something interesting available that people will enjoy playing. There are many ways to promote your game — most of them being free, so even if you're struggling to make a living as an indie dev with zero budget you can still do a lot to let people know about your great new game. Promoting the game helps a lot when [monetizing](/en-US/docs/Games/Publishing_games/Game_monetization) it later on too, so it's important to do it correctly.
@@ -26,7 +27,7 @@ You should definitely create your own website containing all the information abo
26
27
27
28
You should also blog about everything related to your gamedev activities. Write about your development process, nasty bugs you encounter, funny stories, lessons learned, and the ups and downs of being a game developer. Continually publishing information about your games will help educate others, increase your reputation in the community, and further improve SEO. A further option is to publish [monthly reports](https://end3r.com/blog/?s=monthly+report) that summarize all your progress — it helps you see what you've accomplished throughout the month and what's still left to do, and it keeps reminding people that your game is coming out soon — building buzz is always good.
28
29
29
-
While you can create your website from scratch, there are also tools that can help make the process easier. [ManaKeep](https://manakeep.com) is a website builder made for indie game developers and provides a great starting point to create your website.[Presskit()](https://dopresskit.com/) is a press kit builder that helps you create a press page to share with the media.
30
+
While you can create your website from scratch, there are also tools that can help make the process easier. [ManaKeep](https://manakeep.com) is a website builder made for indie game developers and provides a great starting point to create your website. [Presskit()](https://dopresskit.com/) is a press kit builder that helps you create a press page to share with the media.
Copy file name to clipboardExpand all lines: files/en-us/games/publishing_games/index.md
+1
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,7 @@ tags:
10
10
- distribution
11
11
- publishing
12
12
---
13
+
13
14
{{GamesSidebar}}
14
15
15
16
HTML games have a huge advantage over native in terms of publishing and distribution — you have the freedom of distribution, promotion and monetization of your game on the Web, rather than each version being locked into a single store controlled by one company. You can benefit from the web being truly multiplatform. This series of articles looks at the options you have when you want to publish and distribute your game, and earn something out of it while you wait for it to become famous.
0 commit comments