Skip to content

Commit

Permalink
chore: run Prettier on games (#19943)
Browse files Browse the repository at this point in the history
* chore: run Prettier on games

* fix: use prettier-ignore for explicit semicolon

* Update files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md

Co-authored-by: rubiesonthesky <[email protected]>

* chore: use Prettier bracketSameLine

Co-authored-by: Jean-Yves Perrier <[email protected]>
Co-authored-by: rubiesonthesky <[email protected]>
  • Loading branch information
3 people authored Aug 26, 2022
1 parent 6e578cf commit e4783c0
Show file tree
Hide file tree
Showing 71 changed files with 797 additions and 510 deletions.
3 changes: 3 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"bracketSameLine": true
}
115 changes: 63 additions & 52 deletions files/en-us/games/anatomy/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tags:
- Main Loop
- requestAnimationFrame
---

{{GamesSidebar}}

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.
Expand Down Expand Up @@ -55,13 +56,14 @@ But do not immediately assume animations require frame-by-frame control. Simple

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).

<!-- prettier-ignore-start -->
```js
/*
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*/
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*/

;(() => {
function main() {
Expand All @@ -73,22 +75,24 @@ There are two obvious issues with our previous main loop: `main()` pollutes the
main(); // Start the cycle
})();
```
<!-- prettier-ignore-end -->

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.

> **Note:** In practice, it is more common to prevent the next `requestAnimationFrame()` with an if-statement, rather than calling `cancelAnimationFrame()`.
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:

<!-- prettier-ignore-start -->
```js
/*
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*/
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*/

;(() => {
function main() {
Expand All @@ -100,6 +104,7 @@ For the second issue, stopping the main loop, you will need to cancel the call t
main(); // Start the cycle
})();
```
<!-- prettier-ignore-end -->

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.

Expand Down Expand Up @@ -134,15 +139,16 @@ const tNow = window.performance.now();

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.

<!-- prettier-ignore-start -->
```js
/*
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*/
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*/

;(() => {
function main(tFrame) {
Expand All @@ -155,6 +161,7 @@ Back to the topic of the main loop. You will often want to know when your main f
main(); // Start the cycle
})();
```
<!-- prettier-ignore-end -->

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.

Expand All @@ -168,15 +175,16 @@ You will need to make hard decisions about your main loop: how to simulate the a

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.

<!-- prettier-ignore-start -->
```js
/*
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*/
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*/

;(() => {
function main(tFrame) {
Expand All @@ -189,6 +197,7 @@ If your game can hit the maximum refresh rate of any hardware you support then y
main(); // Start the cycle
})();
```
<!-- prettier-ignore-end -->

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:

Expand Down Expand Up @@ -229,34 +238,35 @@ A separate update and draw method could look like the following example. For the

> **Warning:** This example, specifically, is in need of technical review.
<!-- prettier-ignore-start -->
```js
/*
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*
* MyGame.lastRender keeps track of the last provided requestAnimationFrame timestamp.
* MyGame.lastTick keeps track of the last update time. Always increments by tickLength.
* MyGame.tickLength is how frequently the game state updates. It is 20 Hz (50ms) here.
*
* timeSinceTick is the time between requestAnimationFrame callback and last update.
* numTicks is how many updates should have happened between these two rendered frames.
*
* render() is passed tFrame because it is assumed that the render method will calculate
* how long it has been since the most recently passed update tick for
* extrapolation (purely cosmetic for fast devices). It draws the scene.
*
* update() calculates the game state as of a given point in time. It should always
* increment by tickLength. It is the authority for game state. It is passed
* the DOMHighResTimeStamp for the time it represents (which, again, is always
* last update + MyGame.tickLength unless a pause feature is added, etc.)
*
* setInitialState() Performs whatever tasks are leftover before the main loop must run.
* It is just a generic example function that you might have added.
*/
* Starting with the semicolon is in case whatever line of code above this example
* relied on automatic semicolon insertion (ASI). The browser could accidentally
* think this whole example continues from the previous line. The leading semicolon
* marks the beginning of our new line if the previous one was not empty or terminated.
*
* Let us also assume that MyGame is previously defined.
*
* MyGame.lastRender keeps track of the last provided requestAnimationFrame timestamp.
* MyGame.lastTick keeps track of the last update time. Always increments by tickLength.
* MyGame.tickLength is how frequently the game state updates. It is 20 Hz (50ms) here.
*
* timeSinceTick is the time between requestAnimationFrame callback and last update.
* numTicks is how many updates should have happened between these two rendered frames.
*
* render() is passed tFrame because it is assumed that the render method will calculate
* how long it has been since the most recently passed update tick for
* extrapolation (purely cosmetic for fast devices). It draws the scene.
*
* update() calculates the game state as of a given point in time. It should always
* increment by tickLength. It is the authority for game state. It is passed
* the DOMHighResTimeStamp for the time it represents (which, again, is always
* last update + MyGame.tickLength unless a pause feature is added, etc.)
*
* setInitialState() Performs whatever tasks are leftover before the main loop must run.
* It is just a generic example function that you might have added.
*/

;(() => {
function main(tFrame) {
Expand Down Expand Up @@ -293,6 +303,7 @@ A separate update and draw method could look like the following example. For the
main(performance.now()); // Start the cycle
})();
```
<!-- prettier-ignore-end -->

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).

Expand Down
7 changes: 3 additions & 4 deletions files/en-us/games/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tags:
- Games
- Web
---

{{GamesSidebar}}

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.
Expand Down Expand Up @@ -52,10 +53,8 @@ This page lists a number of impressive web technology demos for you to get inspi

- [A Wizard's Lizard](http://www.wizardslizard.com/)
- : Top down Zelda-esque exploration/RPG.

**[Bullet Force](https://www.crazygames.com/game/bullet-force-multiplayer)**
3D multiplayer first-person shooter.

- [Bullet Force](https://www.crazygames.com/game/bullet-force-multiplayer)
- : 3D multiplayer first-person shooter.
- [Elliot Quest](https://elliotquest.com/)
- : 8-bit graphic retro adventure game.
- [RPG MO](https://data.mo.ee/index2.html)
Expand Down
1 change: 1 addition & 0 deletions files/en-us/games/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tags:
- JavaScript Games
- Web
---

{{GamesSidebar}}

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.
Expand Down
1 change: 1 addition & 0 deletions files/en-us/games/introduction/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tags:
- Guide
- Mobile
---

{{GamesSidebar}}

The modern web has quickly become a viable platform not only for creating stunning, high quality games, but also for distributing those games.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tags:
- HTML
- Mobile
---

{{GamesSidebar}}

## Advantages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ tags:
- Web Stores
- distribution
---

{{GamesSidebar}}

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ tags:
- iap
- licensing
---

{{GamesSidebar}}

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.
Expand Down
3 changes: 2 additions & 1 deletion files/en-us/games/publishing_games/game_promotion/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tags:
- blog
- competitions
---

{{GamesSidebar}}

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.
Expand All @@ -26,7 +27,7 @@ You should definitely create your own website containing all the information abo

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.

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.
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.

## Social media

Expand Down
1 change: 1 addition & 0 deletions files/en-us/games/publishing_games/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tags:
- distribution
- publishing
---

{{GamesSidebar}}

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.
Expand Down
Loading

0 comments on commit e4783c0

Please sign in to comment.