From ca1db7a81fa401ad03a20d9de41900e269e057de Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Wed, 24 Aug 2022 18:18:08 -0400 Subject: [PATCH 1/4] chore: run Prettier on games --- files/en-us/games/anatomy/index.md | 123 +++++++------ files/en-us/games/examples/index.md | 7 +- files/en-us/games/index.md | 1 + files/en-us/games/introduction/index.md | 1 + .../index.md | 1 + .../game_distribution/index.md | 1 + .../game_monetization/index.md | 1 + .../publishing_games/game_promotion/index.md | 3 +- files/en-us/games/publishing_games/index.md | 1 + .../2d_collision_detection/index.md | 43 +++-- .../index.md | 26 ++- .../3d_collision_detection/index.md | 49 +++-- .../3d_on_the_web/basic_theory/index.md | 1 + .../index.md | 60 +++--- .../index.md | 49 +++-- .../editor/index.md | 9 +- .../engine/index.md | 45 +++-- .../index.md | 1 + .../index.md | 55 +++--- .../3d_on_the_web/glsl_shaders/index.md | 53 ++++-- .../games/techniques/3d_on_the_web/index.md | 1 + .../techniques/3d_on_the_web/webvr/index.md | 14 +- .../games/techniques/async_scripts/index.md | 11 +- .../techniques/audio_for_web_games/index.md | 76 ++++---- .../desktop_with_gamepad/index.md | 59 +++--- .../desktop_with_mouse_and_keyboard/index.md | 33 +++- .../techniques/control_mechanisms/index.md | 1 + .../control_mechanisms/mobile_touch/index.md | 21 ++- .../control_mechanisms/other/index.md | 62 ++++--- .../techniques/controls_gamepad_api/index.md | 9 +- .../techniques/crisp_pixel_art_look/index.md | 7 +- .../index.md | 12 +- files/en-us/games/techniques/index.md | 1 + .../en-us/games/techniques/tilemaps/index.md | 9 +- .../index.md | 8 +- .../index.md | 21 +-- .../techniques/webrtc_data_channels/index.md | 1 + files/en-us/games/tools/asm.js/index.md | 3 +- files/en-us/games/tools/index.md | 1 + .../animations_and_tweens/index.md | 13 +- .../bounce_off_the_walls/index.md | 1 + .../build_the_brick_field/index.md | 35 ++-- .../2d_breakout_game_phaser/buttons/index.md | 5 +- .../collision_detection/index.md | 1 + .../extra_lives/index.md | 37 +++- .../game_over/index.md | 3 +- .../2d_breakout_game_phaser/index.md | 1 + .../initialize_the_framework/index.md | 36 ++-- .../index.md | 7 +- .../move_the_ball/index.md | 1 + .../2d_breakout_game_phaser/physics/index.md | 10 +- .../player_paddle_and_controls/index.md | 15 +- .../randomizing_gameplay/index.md | 3 +- .../2d_breakout_game_phaser/scaling/index.md | 3 +- .../the_score/index.md | 6 +- .../win_the_game/index.md | 3 +- .../bounce_off_the_walls/index.md | 5 +- .../build_the_brick_field/index.md | 3 +- .../collision_detection/index.md | 12 +- .../create_the_canvas_and_draw_on_it/index.md | 42 +++-- .../finishing_up/index.md | 1 + .../game_over/index.md | 9 +- .../2d_breakout_game_pure_javascript/index.md | 1 + .../mouse_controls/index.md | 3 +- .../move_the_ball/index.md | 1 + .../paddle_and_keyboard_controls/index.md | 3 +- .../track_the_score_and_win/index.md | 15 +- .../index.md | 173 ++++++++++++------ files/en-us/games/tutorials/index.md | 1 + .../tutorials/touch_event_horizon/index.md | 1 + 70 files changed, 805 insertions(+), 525 deletions(-) diff --git a/files/en-us/games/anatomy/index.md b/files/en-us/games/anatomy/index.md index f534361e99dfaa2..53f752c4d25e022 100644 --- a/files/en-us/games/anatomy/index.md +++ b/files/en-us/games/anatomy/index.md @@ -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. @@ -57,13 +58,13 @@ There are two obvious issues with our previous main loop: `main()` pollutes the ```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() { window.requestAnimationFrame(main); @@ -82,15 +83,15 @@ For the second issue, stopping the main loop, you will need to cancel the call t ```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() { MyGame.stopMain = window.requestAnimationFrame(main); @@ -136,15 +137,15 @@ Back to the topic of the main loop. You will often want to know when your main f ```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) { MyGame.stopMain = window.requestAnimationFrame(main); @@ -170,15 +171,15 @@ If your game can hit the maximum refresh rate of any hardware you support then y ```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) { MyGame.stopMain = window.requestAnimationFrame(main); @@ -231,34 +232,34 @@ A separate update and draw method could look like the following example. For the ```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) { MyGame.stopMain = window.requestAnimationFrame(main); const nextTick = MyGame.lastTick + MyGame.tickLength; diff --git a/files/en-us/games/examples/index.md b/files/en-us/games/examples/index.md index 969da92d42278e2..c8f13613a68cd10 100644 --- a/files/en-us/games/examples/index.md +++ b/files/en-us/games/examples/index.md @@ -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. @@ -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) diff --git a/files/en-us/games/index.md b/files/en-us/games/index.md index 3aabedf6ce91938..0e24a3674e7e6c6 100644 --- a/files/en-us/games/index.md +++ b/files/en-us/games/index.md @@ -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. diff --git a/files/en-us/games/introduction/index.md b/files/en-us/games/introduction/index.md index 954b708a7969116..4b8cdb274e99b41 100644 --- a/files/en-us/games/introduction/index.md +++ b/files/en-us/games/introduction/index.md @@ -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. diff --git a/files/en-us/games/introduction_to_html5_game_development/index.md b/files/en-us/games/introduction_to_html5_game_development/index.md index 971360e38d374ef..aec27d0c768dbdf 100644 --- a/files/en-us/games/introduction_to_html5_game_development/index.md +++ b/files/en-us/games/introduction_to_html5_game_development/index.md @@ -7,6 +7,7 @@ tags: - HTML - Mobile --- + {{GamesSidebar}} ## Advantages diff --git a/files/en-us/games/publishing_games/game_distribution/index.md b/files/en-us/games/publishing_games/game_distribution/index.md index 624e397da8ac3ad..8d7303d1d6c4ec1 100644 --- a/files/en-us/games/publishing_games/game_distribution/index.md +++ b/files/en-us/games/publishing_games/game_distribution/index.md @@ -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. diff --git a/files/en-us/games/publishing_games/game_monetization/index.md b/files/en-us/games/publishing_games/game_monetization/index.md index 4569b9a6b569497..c48793e0b27524e 100644 --- a/files/en-us/games/publishing_games/game_monetization/index.md +++ b/files/en-us/games/publishing_games/game_monetization/index.md @@ -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. diff --git a/files/en-us/games/publishing_games/game_promotion/index.md b/files/en-us/games/publishing_games/game_promotion/index.md index fb08b021cef5896..4c65bbebc01375a 100644 --- a/files/en-us/games/publishing_games/game_promotion/index.md +++ b/files/en-us/games/publishing_games/game_promotion/index.md @@ -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. @@ -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 diff --git a/files/en-us/games/publishing_games/index.md b/files/en-us/games/publishing_games/index.md index 2cf1d9e19fe8cad..3249889fb441ee5 100644 --- a/files/en-us/games/publishing_games/index.md +++ b/files/en-us/games/publishing_games/index.md @@ -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. diff --git a/files/en-us/games/techniques/2d_collision_detection/index.md b/files/en-us/games/techniques/2d_collision_detection/index.md index e7f39c178765c98..0f47410a1e120a5 100644 --- a/files/en-us/games/techniques/2d_collision_detection/index.md +++ b/files/en-us/games/techniques/2d_collision_detection/index.md @@ -7,6 +7,7 @@ tags: - JavaScript - collision detection --- + {{GamesSidebar}} Algorithms to detect collision in 2D games depend on the type of shapes that can collide (e.g. Rectangle to Rectangle, Rectangle to Circle, Circle to Circle). Generally you will have a simple generic shape that covers the entity known as a "hitbox" so even though collision may not be pixel perfect, it will look good enough and be performant across multiple entities. This article provides a review of the most common techniques used to provide collision detection in 2D games. @@ -17,25 +18,33 @@ One of the simpler forms of collision detection is between two rectangles that a ```html hidden
-

Move the rectangle with arrow keys. Green means collision, blue means no collision.

+

+ Move the rectangle with arrow keys. Green means collision, blue means no + collision. +

``` ```js Crafty.init(200, 200); -const dim1 = {x: 5, y: 5, w: 50, h: 50} -const dim2 = {x: 20, y: 10, w: 60, h: 40} +const dim1 = { x: 5, y: 5, w: 50, h: 50 }; +const dim2 = { x: 20, y: 10, w: 60, h: 40 }; const rect1 = Crafty.e("2D, Canvas, Color").attr(dim1).color("red"); -const rect2 = Crafty.e("2D, Canvas, Color, Keyboard, Fourway").fourway(2).attr(dim2).color("blue"); +const rect2 = Crafty.e("2D, Canvas, Color, Keyboard, Fourway") + .fourway(2) + .attr(dim2) + .color("blue"); rect2.bind("EnterFrame", function () { - if (rect1.x < rect2.x + rect2.w && - rect1.x + rect1.w > rect2.x && - rect1.y < rect2.y + rect2.h && - rect1.h + rect1.y > rect2.y) { + if ( + rect1.x < rect2.x + rect2.w && + rect1.x + rect1.w > rect2.x && + rect1.y < rect2.y + rect2.h && + rect1.h + rect1.y > rect2.y + ) { // Collision detected! this.color("green"); } else { @@ -55,7 +64,10 @@ Another simple shape for collision detection is between two circles. This algori ```html hidden
-

Move the circle with arrow keys. Green means collision, blue means no collision.

+

+ Move the circle with arrow keys. Green means collision, blue means no + collision. +

``` @@ -69,8 +81,8 @@ Another simple shape for collision detection is between two circles. This algori ```js Crafty.init(200, 200); -const dim1 = {x: 5, y: 5} -const dim2 = {x: 20, y: 20} +const dim1 = { x: 5, y: 5 }; +const dim2 = { x: 20, y: 20 }; Crafty.c("Circle", { circle(radius, color) { @@ -78,7 +90,7 @@ Crafty.c("Circle", { this.w = this.h = radius * 2; this.color = color || "#000000"; - this.bind("Move", Crafty.DrawManager.drawAll) + this.bind("Move", Crafty.DrawManager.drawAll); return this; }, @@ -97,12 +109,15 @@ Crafty.c("Circle", { ctx.closePath(); ctx.fill(); ctx.restore(); - } + }, }); const circle1 = Crafty.e("2D, Canvas, Circle").attr(dim1).circle(15, "red"); -const circle2 = Crafty.e("2D, Canvas, Circle, Fourway").fourway(2).attr(dim2).circle(20, "blue"); +const circle2 = Crafty.e("2D, Canvas, Circle, Fourway") + .fourway(2) + .attr(dim2) + .circle(20, "blue"); circle2.bind("EnterFrame", () => { const dx = circle1.x - circle2.x; diff --git a/files/en-us/games/techniques/3d_collision_detection/bounding_volume_collision_detection_with_three.js/index.md b/files/en-us/games/techniques/3d_collision_detection/bounding_volume_collision_detection_with_three.js/index.md index 5dc3de715ac5489..8fa641b716dfc01 100644 --- a/files/en-us/games/techniques/3d_collision_detection/bounding_volume_collision_detection_with_three.js/index.md +++ b/files/en-us/games/techniques/3d_collision_detection/bounding_volume_collision_detection_with_three.js/index.md @@ -11,6 +11,7 @@ tags: - collision detection - three.js --- + {{GamesSidebar}} This article shows how to implement **collision detection between bounding boxes and spheres using the Three.js** library. It is assumed that before reading this you have read our [3D collision detection](/en-US/docs/Games/Techniques/3D_collision_detection) introductory article first, and have basic knowledge about Three.js. @@ -26,12 +27,14 @@ To create a **`Box3` instance**, we need to provide the **lower and upper bounda ```js const knot = new THREE.Mesh( new THREE.TorusKnotGeometry(0.5, 0.1), - new MeshNormalMaterial({})); + new MeshNormalMaterial({}) +); knot.geometry.computeBoundingBox(); const knotBBox = new Box3( knot.geometry.boundingBox.min, - knot.geometry.boundingBox.max); + knot.geometry.boundingBox.max +); ``` > **Note:** The `boundingBox` property takes the `Geometry` itself as reference, and not the `Mesh`. So any transformations such as scale, position, etc. applied to the `Mesh` will be ignored while computing the calculating box. @@ -41,7 +44,8 @@ A more simple alternative that fixes the previous issue is to set those boundari ```js const knot = new THREE.Mesh( new THREE.TorusKnotGeometry(0.5, 0.1), - new MeshNormalMaterial({})); + new MeshNormalMaterial({}) +); const knotBBox = new Box3(new THREE.Vector3(), new THREE.Vector3()); knotBBox.setFromObject(knot); @@ -54,11 +58,13 @@ Instantiating **`Sphere` objects** is similar. We need to provide the sphere's c ```js const knot = new THREE.Mesh( new THREE.TorusKnotGeometry(0.5, 0.1), - new MeshNormalMaterial({})); + new MeshNormalMaterial({}) +); const knotBSphere = new Sphere( knot.position, - knot.geometry.boundingSphere.radius); + knot.geometry.boundingSphere.radius +); ``` Unfortunately, there is no equivalent of `Box3.setFromObject` for Sphere instances. So if we apply transformations or change the position of the `Mesh`, we need to manually update the bounding sphere. For instance: @@ -108,12 +114,12 @@ Unfortunately this test is not implemented in Three.js, but we can patch Sphere THREE.Sphere.__closest = new THREE.Vector3(); THREE.Sphere.prototype.intersectsBox = function (box) { - // get box closest point to sphere center by clamping - THREE.Sphere.__closest.set(this.center.x, this.center.y, this.center.z); - THREE.Sphere.__closest.clamp(box.min, box.max); + // get box closest point to sphere center by clamping + THREE.Sphere.__closest.set(this.center.x, this.center.y, this.center.z); + THREE.Sphere.__closest.clamp(box.min, box.max); - const distance = this.center.distanceToSquared(THREE.Sphere.__closest); - return distance < (this.radius * this.radius); + const distance = this.center.distanceToSquared(THREE.Sphere.__closest); + return distance < this.radius * this.radius; }; ``` diff --git a/files/en-us/games/techniques/3d_collision_detection/index.md b/files/en-us/games/techniques/3d_collision_detection/index.md index 8284030b0e6c368..36d50c447e805b7 100644 --- a/files/en-us/games/techniques/3d_collision_detection/index.md +++ b/files/en-us/games/techniques/3d_collision_detection/index.md @@ -8,6 +8,7 @@ tags: - bounding boxes - collision detection --- + {{GamesSidebar}} This article provides an introduction to the different bounding volume techniques used to implement collision detection in 3D environments. Followup articles will cover implementations in specific 3D libraries. @@ -35,9 +36,14 @@ Or in JavaScript: ```js function isPointInsideAABB(point, box) { - return (point.x >= box.minX && point.x <= box.maxX) && - (point.y >= box.minY && point.y <= box.maxY) && - (point.z >= box.minZ && point.z <= box.maxZ); + return ( + point.x >= box.minX && + point.x <= box.maxX && + point.y >= box.minY && + point.y <= box.maxY && + point.z >= box.minZ && + point.z <= box.maxZ + ); } ``` @@ -56,9 +62,14 @@ And in JavaScript, we'd use this: ```js function intersect(a, b) { - return (a.minX <= b.maxX && a.maxX >= b.minX) && - (a.minY <= b.maxY && a.maxY >= b.minY) && - (a.minZ <= b.maxZ && a.maxZ >= b.minZ); + return ( + a.minX <= b.maxX && + a.maxX >= b.minX && + a.minY <= b.maxY && + a.maxY >= b.minY && + a.minZ <= b.maxZ && + a.maxZ >= b.minZ + ); } ``` @@ -82,9 +93,11 @@ Or in JavaScript: ```js function isPointInsideSphere(point, sphere) { // we are using multiplications because is faster than calling Math.pow - const distance = Math.sqrt((point.x - sphere.x) * (point.x - sphere.x) + - (point.y - sphere.y) * (point.y - sphere.y) + - (point.z - sphere.z) * (point.z - sphere.z)); + const distance = Math.sqrt( + (point.x - sphere.x) * (point.x - sphere.x) + + (point.y - sphere.y) * (point.y - sphere.y) + + (point.z - sphere.z) * (point.z - sphere.z) + ); return distance < sphere.radius; } ``` @@ -107,10 +120,12 @@ Or in JavaScript: ```js function intersect(sphere, other) { // we are using multiplications because it's faster than calling Math.pow - const distance = Math.sqrt((sphere.x - other.x) * (sphere.x - other.x) + - (sphere.y - other.y) * (sphere.y - other.y) + - (sphere.z - other.z) * (sphere.z - other.z)); - return distance < (sphere.radius + other.radius); + const distance = Math.sqrt( + (sphere.x - other.x) * (sphere.x - other.x) + + (sphere.y - other.y) * (sphere.y - other.y) + + (sphere.z - other.z) * (sphere.z - other.z) + ); + return distance < sphere.radius + other.radius; } ``` @@ -130,9 +145,11 @@ function intersect(sphere, box) { const z = Math.max(box.minZ, Math.min(sphere.z, box.maxZ)); // this is the same as isPointInsideSphere - const distance = Math.sqrt((x - sphere.x) * (x - sphere.x) + - (y - sphere.y) * (y - sphere.y) + - (z - sphere.z) * (z - sphere.z)); + const distance = Math.sqrt( + (x - sphere.x) * (x - sphere.x) + + (y - sphere.y) * (y - sphere.y) + + (z - sphere.z) * (z - sphere.z) + ); return distance < sphere.radius; } diff --git a/files/en-us/games/techniques/3d_on_the_web/basic_theory/index.md b/files/en-us/games/techniques/3d_on_the_web/basic_theory/index.md index f9aced300ff9f60..c5c9868889f67ed 100644 --- a/files/en-us/games/techniques/3d_on_the_web/basic_theory/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/basic_theory/index.md @@ -14,6 +14,7 @@ tags: - vertex - vertices --- + {{GamesSidebar}} This article explains all of the basic theory that's useful to know when you are getting started working with 3D. diff --git a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md index af639c4a0e79a35..d44f03a87e43832 100644 --- a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md @@ -9,6 +9,7 @@ tags: - Web - WebGL --- + {{GamesSidebar}} The [WebVR](/en-US/docs/Games/Techniques/3D_on_the_web/WebVR) and [WebGL](/en-US/docs/Web/API/WebGL_API) APIs already enable us to start creating virtual reality (VR) experiences inside web browsers, but the community is still waiting for tools and libraries to appear, to make this easier. Mozilla's [A-Frame](https://aframe.io/) framework provides a markup language allowing us to build 3D VR landscapes using a system familiar to web developers, which follows game development coding principles; this is useful for quickly and successfully building prototypes and demos, without having to write a lot of JavaScript or GLSL. This article explains how to get up and running with A-Frame, and how to use it to build up a simple demo. @@ -37,7 +38,7 @@ The first step is to create an HTML document — inside your project directory, - + MDN Games: A-Frame demo @@ -58,8 +59,7 @@ A scene is the place where everything happens. When creating new objects in the Let's create the scene by adding an `` element inside the `` element: ```html - - + ``` ### Adding a cube @@ -67,11 +67,7 @@ Let's create the scene by adding an `` element inside the `` elem Adding the cube to the scene is done by adding a simple [``](https://aframe.io/docs/primitives/a-box.html) element inside the `` element. Add it now: ```html - - + ``` It contains a few parameters already defined: `color`, `position` and `rotation` — these are fairly obvious, and define the base color of the cube, the position inside the 3D scene, and the rotation of the cube. @@ -114,7 +110,8 @@ A camera entity can be created by adding an [``](https://aframe.io/doc cursor-visible="true" cursor-scale="2" cursor-color="#0095DD" - cursor-opacity="0.5"> + cursor-opacity="0.5" +> ``` @@ -125,16 +122,9 @@ We've also defined a cursor for the given camera, using the `cursor-*` attribute The basic light types in A-Frame are directional and ambient. The first type is a directional light placed somewhere on the scene while the second one reflects the light from the first type, so it looks more natural; this can be set globally. Add the new code below your previous additions — this uses the standard `` element: ```html - - - + + ``` The directional light has a white color, its intensity is set to `0.5`, and it is placed at position `-1 1 2`. The ambient light only needs a color, which is also white. @@ -151,7 +141,8 @@ We have a cube on the scene already; now let's try adding more shapes. We are no radiusTubular: 0.1; segmentsTubular: 12;" rotation="10 0 0" - position="-3 1 0"> + position="-3 1 0" +> ``` @@ -173,7 +164,8 @@ The torus is now visible on the scene, but its color doesn't look very good — roughness: 0.1; metalness: 0.5;" rotation="10 0 0" - position="-3 1 0"> + position="-3 1 0" +> ``` @@ -184,12 +176,12 @@ In the new `material` attribute, we set up the `color` of the material, then its It is possible to populate the scene with entities created using JavaScript too, so let's use it to add a third shape, a cylinder. Add a new {{htmlelement("script")}} element at the end of the `` element, just after the `` element, then add the following JavaScript code inside it: ```js -const scene = document.querySelector('a-scene'); -const cylinder = document.createElement('a-cylinder'); -cylinder.setAttribute('color', '#FF9500'); -cylinder.setAttribute('height', '2'); -cylinder.setAttribute('radius', '0.75'); -cylinder.setAttribute('position', '3 1 0'); +const scene = document.querySelector("a-scene"); +const cylinder = document.createElement("a-cylinder"); +cylinder.setAttribute("color", "#FF9500"); +cylinder.setAttribute("height", "2"); +cylinder.setAttribute("radius", "0.75"); +cylinder.setAttribute("position", "3 1 0"); scene.appendChild(cylinder); ``` @@ -208,10 +200,7 @@ We've already used `rotation` and `position` to move the shapes on the scene, an There's a special [``](https://aframe.io/docs/core/animation.html) entity that can help us animate elements. Add the `` element seen below to the `` element as a child, as shown: ```html - + `](https://aframe.io/docs/core/animation.html) direction="alternate" dur="4000" repeat="indefinite" - easing="ease"> + easing="ease" + > ``` @@ -242,14 +232,16 @@ We can also add animation to entities with custom geometry like the torus, in mu roughness: 0.1; metalness: 0.5;" rotation="10 0 0" - position="-3 1 0"> + position="-3 1 0" +> + easing="linear" + > ``` @@ -265,7 +257,7 @@ let t = 0; function render() { t += 0.01; requestAnimationFrame(render); - cylinder.setAttribute('position', `3 ${Math.sin(t * 2) + 1} 0`); + cylinder.setAttribute("position", `3 ${Math.sin(t * 2) + 1} 0`); } render(); ``` diff --git a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_babylon.js/index.md b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_babylon.js/index.md index 3479c9632486959..a837bd57e9c443b 100644 --- a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_babylon.js/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_babylon.js/index.md @@ -7,6 +7,7 @@ tags: - Beginner - WebGL --- + {{GamesSidebar}} [Babylon.js](https://www.babylonjs.com/) is one of the most popular 3D game engines used by developers. As with any other 3D library it provides built-in functions to help you implement common 3D functionality more quickly. In this article we'll take you through the real basics of using Babylon.js, including setting up a development environment, structuring the necessary HTML, and writing the JavaScript code. @@ -29,21 +30,29 @@ Here's the HTML structure we will use: ```html - - + + MDN Games: Babylon.js demo - - - - - - + + + + + + ``` @@ -78,8 +87,8 @@ To make the scene actually visible we have to render it. Add these lines at the ```js function renderLoop() { - scene.render(); -}; + scene.render(); +} engine.runRenderLoop(renderLoop); ``` @@ -90,7 +99,11 @@ We're using the engine's `runRenderLoop()` method to execute the `renderLoop()` Now the setup code is in place we need to think about implementing the standard scene components: camera, light and objects. Let's start with the camera — add this line to your code below the scene creation and the line where we defined the `clearColor`. ```js -const camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(0, 0, -10), scene); +const camera = new BABYLON.FreeCamera( + "camera", + new BABYLON.Vector3(0, 0, -10), + scene +); ``` There are many [cameras](https://doc.babylonjs.com/divingDeeper/cameras) available in Babylon.js; `FreeCamera` is the most basic and universal one. To initialize it you need to pass it three parameters: any name you want to use for it, the coordinates where you want it to be positioned in the 3D space, and the scene you want to add it to. @@ -102,7 +115,11 @@ There are many [cameras](https://doc.babylonjs.com/divingDeeper/cameras) availab There are various [light sources](https://doc.babylonjs.com/divingDeeper/lights/lights_introduction#types-of-lights) available in Babylon.js. The most basic one is the `PointLight`, which works like a flashlight — shining a spotlight in a given direction. Add the following line below your camera definition: ```js -const light = new BABYLON.PointLight("light", new BABYLON.Vector3(10, 10, 0), scene); +const light = new BABYLON.PointLight( + "light", + new BABYLON.Vector3(10, 10, 0), + scene +); ``` The parameters are very similar to the previously defined camera: the name of the light, a position in 3D space and the scene to which the light is added. diff --git a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/editor/index.md b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/editor/index.md index 36bf0fc7e3da22f..76a4c3947cb4f00 100644 --- a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/editor/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/editor/index.md @@ -16,6 +16,7 @@ tags: - editor - rendering --- + Instead of coding everything from scratch you can also use the online **PlayCanvas editor**. This can be a more pleasant working environment if you are not someone who likes to code. ## Creating an account @@ -117,19 +118,17 @@ Animating 3D models might be considered an [advanced](https://developer.playcanv If you double click on it, you'll be moved to a code editor. As you can see, the file contains some boilerplate code already: ```js -pc.script.create('boxAnimation', function (app) { +pc.script.create("boxAnimation", function (app) { class BoxAnimation { constructor(entity) { this.entity = entity; } // Called once after all resources are loaded and before the first update - initialize() { - } + initialize() {} // Called every frame, dt is time in seconds since last update - update(dt) { - } + update(dt) {} } return BoxAnimation; diff --git a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/engine/index.md b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/engine/index.md index 7fbda2f565f9995..0eafc02bc5bf2e4 100644 --- a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/engine/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/engine/index.md @@ -15,6 +15,7 @@ tags: - lighting - rendering --- + {{GamesSidebar}} Built for modern browsers, **PlayCanvas** is a fully-featured 3D game engine with resource loading, an entity and component system, advanced graphics manipulation, collision and physics engine (built with [ammo.js](https://github.com/kripken/ammo.js/)), audio, and facilities to handle control inputs from various devices (including gamepads). @@ -41,22 +42,28 @@ Here's the HTML structure we will use. ```html - - + + MDN Games: PlayCanvas demo - - - - - - + + + + + + ``` @@ -89,7 +96,7 @@ Now when the setup code is in place we need to think about implementing the stan ```js const camera = new pc.Entity(); camera.addComponent("camera", { - clearColor: new pc.Color(0.8, 0.8, 0.8) + clearColor: new pc.Color(0.8, 0.8, 0.8), }); app.root.addChild(camera); @@ -127,7 +134,7 @@ The basic light types in PlayCanvas are directional and ambient. The first type ```js const light = new pc.Entity(); -light.addComponent('light'); +light.addComponent("light"); app.root.addChild(light); light.rotate(45, 0, 0); ``` @@ -228,8 +235,8 @@ We already used `translate` or `rotate` to adjust the position of the shapes; we ```js let timer = 0; app.on("update", (deltaTime) => { - timer += deltaTime; - // code executed on every frame + timer += deltaTime; + // code executed on every frame }); ``` @@ -240,7 +247,7 @@ The callback takes the `deltaTime` as the parameter, so we have the relative tim Rotating is quite easy — all you need to do is to add a defined value to the given direction of rotation on each frame. Add this line of code inside the `app.on("update")` callback function, right after the addition of the `deltaTime` to the `timer` variable: ```js -box.rotate(deltaTime*10, deltaTime*20, deltaTime*30); +box.rotate(deltaTime * 10, deltaTime * 20, deltaTime * 30); ``` It will rotate the `box` by `deltaTime*10` on the `x` axis, `deltaTime*20` on the `y` axis and `deltaTime*30` on the `z` axis, on very frame — giving us a smooth animation. @@ -262,7 +269,7 @@ Now onto the movement part. Beside rotation and scaling we can also move objects around the scene. Add the following code to achieve that. ```js -cone.setPosition(2, Math.sin(timer*2), 0); +cone.setPosition(2, Math.sin(timer * 2), 0); ``` This will move the `cone` up and down by applying the `sin` value to the `y` axis on each frame, with a little bit of adjustment to make it look cooler. Try changing the value to see how it affects the animation. diff --git a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/index.md b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/index.md index 008d4022d575974..9c49656219b9a86 100644 --- a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_playcanvas/index.md @@ -14,6 +14,7 @@ tags: - lighting - rendering --- + {{GamesSidebar}} **PlayCanvas** is a popular 3D WebGL game engine, originally created by Will Eastcott and Dave Evans. It is [open sourced on GitHub](https://github.com/playcanvas/engine), with an [editor](https://developer.playcanvas.com/en/user-manual/designer/) available online and good [documentation](https://developer.playcanvas.com/en/). The online editor is free for public projects with up to two team members, but there are also [paid plans](https://playcanvas.com/plans) if you'd like to run a commercial private project with more developers. diff --git a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md index 11339fe66839585..f0fd17f94553abd 100644 --- a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md @@ -14,6 +14,7 @@ tags: - rendering - three.js --- + {{GamesSidebar}} A typical 3D scene in a game — even the simplest one — contains standard items like shapes located in a coordinate system, a camera to actually see them, lights and materials to make it look better, animations to make it look alive, etc. **Three.js**, as with any other 3D library, provides built-in helper functions to help you implement common 3D functionality more quickly. In this article we'll take you through the real basics of using Three, including setting up a development environment, structuring the necessary HTML, the fundamental objects of Three, and how to build up a basic demo. @@ -36,22 +37,28 @@ Here's the HTML structure we will use: ```html - - - MDN Games: Three.js demo - - - - - - + + + MDN Games: Three.js demo + + + + + + ``` @@ -64,9 +71,9 @@ Before reading further, copy this code to a new text file, and save it in your w A renderer is a tool which displays scenes right in your browser. There are a few different renderers: WebGL is the default, and others you can use are Canvas, SVG, CSS, and DOM. They differ in how everything is rendered, so the WebGL implementation will implement differently than the CSS one. Despite the variety of ways they achieve the goal, the experience will look the same for the user. Thanks to this approach, a fallback can be used, if a desired technology is not supported by the browser. ```js -const renderer = new THREE.WebGLRenderer({antialias:true}); +const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(WIDTH, HEIGHT); -renderer.setClearColor(0xDDDDDD, 1); +renderer.setClearColor(0xdddddd, 1); document.body.appendChild(renderer.domElement); ``` @@ -89,7 +96,7 @@ Later, we will be using the `.add()` method, to add objects to this scene. We have the rendered scene, but we still need to add a camera to view our handiwork — imagine a movie set without any cameras. The following lines put the camera in place in the 3D coordinate system, and point it in the direction of our scene, so we can finally see something: ```js -const camera = new THREE.PerspectiveCamera(70, WIDTH/HEIGHT); +const camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT); camera.position.z = 50; scene.add(camera); ``` @@ -137,7 +144,7 @@ In this case, we define a simple cube that is 10 x 10 x 10 units. The geometry i A material is what covers an object, the colors, or textures on its surface. In our case, we will choose a simple blue color to paint our box. There are a number of predefined materials which can be used: Basic, Phong, Lambert. Let's play with the last two later, but for now, the Basic one should be enough: ```js -const basicMaterial = new THREE.MeshBasicMaterial({color: 0x0095DD}); +const basicMaterial = new THREE.MeshBasicMaterial({ color: 0x0095dd }); ``` Add this line below the previously added. @@ -190,7 +197,7 @@ Now onto more shapes and materials. What might happen when you add a torus, wrap ```js const torusGeometry = new THREE.TorusGeometry(7, 1, 6, 12); -const phongMaterial = new THREE.MeshPhongMaterial({color: 0xFF9500}); +const phongMaterial = new THREE.MeshPhongMaterial({ color: 0xff9500 }); const torus = new THREE.Mesh(torusGeometry, phongMaterial); scene.add(torus); ``` @@ -201,7 +208,7 @@ We can choose more fun predefined shapes. Let's play some more. Add the followin ```js const dodecahedronGeometry = new THREE.DodecahedronGeometry(7); -const lambertMaterial = new THREE.MeshLambertMaterial({color: 0xEAEFF2}); +const lambertMaterial = new THREE.MeshLambertMaterial({ color: 0xeaeff2 }); const dodecahedron = new THREE.Mesh(dodecahedronGeometry, lambertMaterial); dodecahedron.position.x = 25; scene.add(dodecahedron); @@ -216,7 +223,7 @@ As mentioned above, the new objects currently just look black. To have both, the There are various types of light sources available in Three.js. The most basic is `PointLight`, which works like a flashlight, shining a spotlight in a defined direction. Add the following lines, below your shape definitions: ```js -const light = new THREE.PointLight(0xFFFFFF); +const light = new THREE.PointLight(0xffffff); light.position.set(-10, 15, 50); scene.add(light); ``` @@ -265,7 +272,7 @@ Now, onto movement. Aside from rotation, and scaling, we can additionally move objects around the scene. Add the following, again just below our `requestAnimationFrame()` invocation: ```js -dodecahedron.position.y = -7*Math.sin(t*2); +dodecahedron.position.y = -7 * Math.sin(t * 2); ``` This will move the dodecahedron up and down, by applying the `sin()` value to the y-axis on each frame, and a little adjustment to make it look cooler. Try changing these values, to see how it affects the animations. diff --git a/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md b/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md index 3021ef63817ee99..9baaf370098a456 100644 --- a/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/glsl_shaders/index.md @@ -10,6 +10,7 @@ tags: - three.js - vertex shader --- + {{GamesSidebar}} Shaders use GLSL (OpenGL Shading Language), a special OpenGL Shading Language with syntax similar to C. GLSL is executed directly by the graphics pipeline. There are [several kinds of shaders](https://www.khronos.org/opengl/wiki/Shader), but two are commonly used to create graphics on the web: Vertex Shaders and Fragment (Pixel) Shaders. Vertex Shaders transform shape positions into 3D drawing coordinates. Fragment Shaders compute the renderings of a shape's colors and other attributes. @@ -56,23 +57,30 @@ Here's the HTML structure we will use. - + MDN Games: Shaders demo @@ -132,8 +140,8 @@ Then, create the [`shaderMaterial`](https://threejs.org/docs/#Reference/Material ```js const shaderMaterial = new THREE.ShaderMaterial({ - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent + vertexShader: document.getElementById("vertexShader").textContent, + fragmentShader: document.getElementById("fragmentShader").textContent, }); ``` @@ -159,14 +167,14 @@ It looks exactly the same as the Three.js cube demo but the slightly different p ```html ``` @@ -178,7 +186,7 @@ const HEIGHT = window.innerHeight; const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(WIDTH, HEIGHT); -renderer.setClearColor(0xDDDDDD, 1); +renderer.setClearColor(0xdddddd, 1); document.body.appendChild(renderer.domElement); const scene = new THREE.Scene(); @@ -190,8 +198,8 @@ scene.add(camera); const boxGeometry = new THREE.BoxGeometry(10, 10, 10); const shaderMaterial = new THREE.ShaderMaterial({ - vertexShader: document.getElementById('vertexShader').textContent, - fragmentShader: document.getElementById('fragmentShader').textContent + vertexShader: document.getElementById("vertexShader").textContent, + fragmentShader: document.getElementById("fragmentShader").textContent, }); const cube = new THREE.Mesh(boxGeometry, shaderMaterial); @@ -208,8 +216,15 @@ render(); ### CSS ```css -body { margin: 0; padding: 0; font-size: 0; } -canvas { width: 100%; height: 100%; } +body { + margin: 0; + padding: 0; + font-size: 0; +} +canvas { + width: 100%; + height: 100%; +} ``` ### Result diff --git a/files/en-us/games/techniques/3d_on_the_web/index.md b/files/en-us/games/techniques/3d_on_the_web/index.md index 5fc8f2f10842d5e..5e21c054ad01d49 100644 --- a/files/en-us/games/techniques/3d_on_the_web/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/index.md @@ -10,6 +10,7 @@ tags: - WebVR - three.js --- + {{GamesSidebar}} For rich gaming experiences on the web, the weapon of choice is WebGL, which is rendered on HTML {{htmlelement("canvas")}}. WebGL is basically an OpenGL ES 2.0 for the Web — it's a JavaScript API providing tools to build rich interactive animations and of course, also games. You can generate and render dynamic 3D graphics with JavaScript that is hardware accelerated. diff --git a/files/en-us/games/techniques/3d_on_the_web/webvr/index.md b/files/en-us/games/techniques/3d_on_the_web/webvr/index.md index 29f65f3236ebb1f..51f3eb664517332 100644 --- a/files/en-us/games/techniques/3d_on_the_web/webvr/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/webvr/index.md @@ -7,6 +7,7 @@ tags: - WebGL - WebVR --- + {{GamesSidebar}} The concept of virtual reality in itself isn't new, but now we have the technology to have it working as it should be, and a JavaScript API to make use of it in web applications. This article introduced WebVR from the perspective of its use in games. @@ -51,8 +52,10 @@ navigator.getVRDevices().then((devices) => { } if (gHMD) { for (let i = 0; i < devices.length; ++i) { - if (devices[i] instanceof PositionSensorVRDevice - && devices[i].hardwareUnitId === gHMD.hardwareUnitId) { + if ( + devices[i] instanceof PositionSensorVRDevice && + devices[i].hardwareUnitId === gHMD.hardwareUnitId + ) { gPositionSensor = devices[i]; break; } @@ -64,8 +67,8 @@ navigator.getVRDevices().then((devices) => { This code will loop through the available devices and assign proper sensors to the headsets — the first `devices` array contains the connected devices, and a check is done to find the {{domxref("HMDVRDevice")}}, and assign it to the `gHMD` variable — using this you can set up the scene, getting the eye parameters, setting the field of view, etc. For example: ```js -function setCustomFOV(up,right,down,left) { - const testFOV = new VRFieldOfView(up,right,down,left); +function setCustomFOV(up, right, down, left) { + const testFOV = new VRFieldOfView(up, right, down, left); gHMD.setFieldOfView(testFOV, testFOV, 0.01, 10000.0); } @@ -79,14 +82,13 @@ function setView() { if (posState.hasPosition) { const format = (axis) => `${axis}${roundToTwo(posState.position[axis])}`; - posPara.textContent = `Position: ${axis('x')} ${axis('y')} ${axis('x')}`; + posPara.textContent = `Position: ${axis("x")} ${axis("y")} ${axis("x")}`; xPos = -posState.position.x * WIDTH * 2; yPos = posState.position.y * HEIGHT * 2; zPos = -posState.position.z > 0.01 ? -posState.position.z : 0.01; } // … - } ``` diff --git a/files/en-us/games/techniques/async_scripts/index.md b/files/en-us/games/techniques/async_scripts/index.md index f2c19eb97211984..9bf319fa78c8119 100644 --- a/files/en-us/games/techniques/async_scripts/index.md +++ b/files/en-us/games/techniques/async_scripts/index.md @@ -7,6 +7,7 @@ tags: - asm.js - async --- + {{GamesSidebar}} Every medium or large game should compile [asm.js](/en-US/docs/Games/Tools/asm.js) code as part of an async script to give the browser the maximum flexibility to optimize the compilation process. In Gecko, async compilation allows the JavaScript engine to compile the asm.js off the main thread when the game is loading and cache the generated machine code so that the game doesn't need to be compiled on subsequent loads (starting in Firefox 28). To see the difference, toggle `javascript.options.parallel_parsing` in `about:config`. @@ -22,7 +23,7 @@ Getting async compilation is easy: when writing your JavaScript, just use the `a or, to do the same thing via script: ```js -const script = document.createElement('script'); +const script = document.createElement("script"); script.src = "file.js"; document.body.appendChild(script); ``` @@ -34,13 +35,15 @@ document.body.appendChild(script); Two common situations in which a script is \*not\* async (as [defined by the HTML spec](https://html.spec.whatwg.org/multipage/scripting.html)) are: ```html - + ``` and ```js -const script = document.createElement('script'); +const script = document.createElement("script"); script.textContent = "code"; document.body.appendChild(script); ``` @@ -51,7 +54,7 @@ What if your code is in a JS string? Instead of using `eval` or `innerHTML`, bot ```js const blob = new Blob([codeString]); -const script = document.createElement('script'); +const script = document.createElement("script"); const url = URL.createObjectURL(blob); script.onload = script.onerror = () => URL.revokeObjectURL(url); script.src = url; diff --git a/files/en-us/games/techniques/audio_for_web_games/index.md b/files/en-us/games/techniques/audio_for_web_games/index.md index d3067d92369a5bf..53566a30da6b14d 100644 --- a/files/en-us/games/techniques/audio_for_web_games/index.md +++ b/files/en-us/games/techniques/audio_for_web_games/index.md @@ -9,6 +9,7 @@ tags: - spatialization - syncing tracks --- + {{GamesSidebar}} Audio is an important part of any game; it adds feedback and atmosphere. Web-based audio is maturing fast, but there are still many browser differences to navigate. We often need to decide which audio parts are essential to our games' experience and which are nice to have but not essential, and devise a strategy accordingly. This article provides a detailed guide to implementing audio for web games, looking at what works currently across as wide a range of platforms as possible. @@ -158,11 +159,11 @@ Here's an example of an audio sprite player — first let's set up the user inte - - - - - + + + + + ``` Now we have buttons with start and stop times in seconds. The "countdown.mp3" MP3 file consists of a number being spoken every 2 seconds, the idea being that we play back that number when the corresponding button is pressed. @@ -170,23 +171,31 @@ Now we have buttons with start and stop times in seconds. The "countdown.mp3" MP Let's add some JavaScript to make this work: ```js -const myAudio = document.getElementById('myAudio'); -const buttons = document.getElementsByTagName('button'); +const myAudio = document.getElementById("myAudio"); +const buttons = document.getElementsByTagName("button"); let stopTime = 0; for (const button of buttons) { - button.addEventListener('click', () => { - myAudio.currentTime = button.getAttribute("data-start"); - stopTime = button.getAttribute("data-stop"); - myAudio.play(); - }, false); + button.addEventListener( + "click", + () => { + myAudio.currentTime = button.getAttribute("data-start"); + stopTime = button.getAttribute("data-stop"); + myAudio.play(); + }, + false + ); } -myAudio.addEventListener('timeupdate', () => { - if (myAudio.currentTime > stopTime) { - myAudio.pause(); - } -}, false); +myAudio.addEventListener( + "timeupdate", + () => { + if (myAudio.currentTime > stopTime) { + myAudio.pause(); + } + }, + false +); ``` > **Note:** You can [try out our audio sprite player live](https://jsfiddle.net/59vwaame/) on JSFiddle. @@ -268,7 +277,9 @@ To see this in action, let's lay out some separate tracks: -

All tracks sourced from jplayer.org

+

+ All tracks sourced from jplayer.org +

``` @@ -285,7 +296,7 @@ const audioCtx = new AudioContext(); Now let's select all the {{htmlelement("li")}} elements; later we can harness these elements to give us access to the track file path and each individual play button. ```js -const trackEls = document.querySelectorAll('li'); +const trackEls = document.querySelectorAll("li"); ``` We want to make sure each file has loaded and been decoded into a buffer before we use it, so let's create an `async` function to allow us to do this: @@ -320,7 +331,7 @@ let offset = 0; function playTrack(audioBuffer) { const trackSource = audioCtx.createBufferSource(); trackSource.buffer = audioBuffer; - trackSource.connect(audioCtx.destination) + trackSource.connect(audioCtx.destination); if (offset === 0) { trackSource.start(); @@ -337,37 +348,34 @@ Finally, let's loop over our `
  • ` elements, grab the correct file for each one ```js trackEls.forEach((el, i) => { - // Get children - const anchor = el.querySelector('a'); - const loadText = el.querySelector('p'); - const playButton = el.querySelector('button'); + const anchor = el.querySelector("a"); + const loadText = el.querySelector("p"); + const playButton = el.querySelector("button"); // Load file loadFile(anchor.href).then((track) => { // Set loading to false - el.dataset.loading = 'false'; + el.dataset.loading = "false"; // Hide loading text - loadText.style.display = 'none'; + loadText.style.display = "none"; // Show button - playButton.style.display = 'inline-block'; + playButton.style.display = "inline-block"; // Allow play on click - playButton.addEventListener('click', () => { - + playButton.addEventListener("click", () => { // Check if context is in suspended state (autoplay policy) - if (audioCtx.state === 'suspended') { + if (audioCtx.state === "suspended") { audioCtx.resume(); } playTrack(track); playButton.dataset.playing = true; - }) - }) - -}) + }); + }); +}); ``` > **Note:** You can [see this demo in action here](https://mdn.github.io/webaudio-examples/multi-track/) and [view the source code here](https://github.com/mdn/webaudio-examples/tree/master/multi-track). diff --git a/files/en-us/games/techniques/control_mechanisms/desktop_with_gamepad/index.md b/files/en-us/games/techniques/control_mechanisms/desktop_with_gamepad/index.md index 5c2238ea0fc4adf..460a4430dd35f51 100644 --- a/files/en-us/games/techniques/control_mechanisms/desktop_with_gamepad/index.md +++ b/files/en-us/games/techniques/control_mechanisms/desktop_with_gamepad/index.md @@ -10,6 +10,7 @@ tags: - JavaScript - controllers --- + {{GamesSidebar}} {{PreviousMenuNext("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms/Other", "Games/Techniques/Control_mechanisms")}} @@ -51,14 +52,14 @@ To update the state of the gamepad's currently pressed buttons we will need a fu ```js function gamepadUpdateHandler() { - buttonsPressed = []; - if (controller.buttons) { - for (let b = 0; b < controller.buttons.length; b++) { - if (controller.buttons[b].pressed) { - buttonsPressed.push(b); - } - } + buttonsPressed = []; + if (controller.buttons) { + for (let b = 0; b < controller.buttons.length; b++) { + if (controller.buttons[b].pressed) { + buttonsPressed.push(b); + } } + } } ``` @@ -66,13 +67,13 @@ We first reset the `buttonsPressed` array to get it ready to store the latest in ```js function gamepadButtonPressedHandler(button) { - let press = false; - for (let i = 0; i < buttonsPressed.length; i++) { - if (buttonsPressed[i] === button) { - press = true; - } + let press = false; + for (let i = 0; i < buttonsPressed.length; i++) { + if (buttonsPressed[i] === button) { + press = true; } - return press; + } + return press; } ``` @@ -98,7 +99,7 @@ function draw() { playerX += 5; } if (gamepadButtonPressedHandler(11)) { - alert('BOOM!'); + alert("BOOM!"); } // … @@ -296,18 +297,18 @@ When on desktop, we can check if the controller is active and show the gamepad c We can offer even more flexibility to the player by giving him main and alternative gamepad movement controls: ```js -if (GamepadAPI.buttons.pressed('DPad-Up','hold')) { - // move player up -} else if (GamepadAPI.buttons.pressed('DPad-Down','hold')) { - // move player down +if (GamepadAPI.buttons.pressed("DPad-Up", "hold")) { + // move player up +} else if (GamepadAPI.buttons.pressed("DPad-Down", "hold")) { + // move player down } -if (GamepadAPI.buttons.pressed('DPad-Left','hold')) { - // move player left +if (GamepadAPI.buttons.pressed("DPad-Left", "hold")) { + // move player left } -if (GamepadAPI.buttons.pressed('DPad-Right','hold')) { - // move player right +if (GamepadAPI.buttons.pressed("DPad-Right", "hold")) { + // move player right } if (GamepadAPI.axes.status) { @@ -332,7 +333,7 @@ Have you noticed that the current value of the axes is evaluated against `0.5`? For the shooting controls, we used the `A` button — when it is held down, a new bullet is spawned, and everything else is handled by the game: ```js -if (GamepadAPI.buttons.pressed('A', 'hold')) { +if (GamepadAPI.buttons.pressed("A", "hold")) { this.spawnBullet(); } ``` @@ -340,13 +341,13 @@ if (GamepadAPI.buttons.pressed('A', 'hold')) { Showing the screen with all the controls looks exactly the same as in the main menu: ```js -this.screenGamepadHelp.visible = GamepadAPI.buttons.pressed('Y', 'hold'); +this.screenGamepadHelp.visible = GamepadAPI.buttons.pressed("Y", "hold"); ``` If the `B` button is pressed, the game is paused: ```js -if (gamepadAPI.buttonPressed('B')) { +if (gamepadAPI.buttonPressed("B")) { this.managePause(); } ``` @@ -356,11 +357,11 @@ if (gamepadAPI.buttonPressed('B')) { We already learned how to control the whole lifecycle of the game: pausing the gameplay, restarting it, or getting back to the main menu. It works smooth on mobile and desktop, and adding gamepad controls is just as straightforward — in the `update()` function, we check to see if the current state status is `paused` — if so, the relevant actions are enabled: ```js -if (GamepadAPI.buttons.pressed('Start')) { +if (GamepadAPI.buttons.pressed("Start")) { this.managePause(); } -if (GamepadAPI.buttons.pressed('Back')) { +if (GamepadAPI.buttons.pressed("Back")) { this.stateBack(); } ``` @@ -368,10 +369,10 @@ if (GamepadAPI.buttons.pressed('Back')) { Similarly, when the `gameover` state status is active, then we can allow the user to restart the game instead of continuing it: ```js -if (GamepadAPI.buttons.pressed('Start')) { +if (GamepadAPI.buttons.pressed("Start")) { this.stateRestart(); } -if (GamepadAPI.buttons.pressed('Back')) { +if (GamepadAPI.buttons.pressed("Back")) { this.stateBack(); } ``` diff --git a/files/en-us/games/techniques/control_mechanisms/desktop_with_mouse_and_keyboard/index.md b/files/en-us/games/techniques/control_mechanisms/desktop_with_mouse_and_keyboard/index.md index 4f47ff8de889f20..c07c03c1f159345 100644 --- a/files/en-us/games/techniques/control_mechanisms/desktop_with_mouse_and_keyboard/index.md +++ b/files/en-us/games/techniques/control_mechanisms/desktop_with_mouse_and_keyboard/index.md @@ -9,6 +9,7 @@ tags: - keyboard - mouse --- + {{GamesSidebar}} {{PreviousMenuNext("Games/Techniques/Control_mechanisms/Mobile_touch", "Games/Techniques/Control_mechanisms/Desktop_with_gamepad", "Games/Techniques/Control_mechanisms")}} @@ -24,8 +25,8 @@ It's also easier to test control-independent features like gameplay on desktop i Let's think about implementing pure JavaScript keyboard/mouse controls in the game first, to see how it would work. First, we'd need an event listener to listen for the pressed keys: ```js -document.addEventListener('keydown', keyDownHandler, false); -document.addEventListener('keyup', keyUpHandler, false); +document.addEventListener("keydown", keyDownHandler, false); +document.addEventListener("keyup", keyUpHandler, false); ``` Whenever any key is pressed down, we're executing the `keyDownHandler` function, and when press finishes we're executing the `keyUpHandler` function, so we know when it's no longer pressed. To do that, we'll hold the information on whether the keys we are interested in are pressed or not: @@ -105,13 +106,25 @@ As I mentioned before, you can write everything on your own, but you can also ta The mouse interactions in the game are focused on clicking the buttons. In Phaser, the buttons you create will take any type of input, whether it's a touch on mobile or a click on desktop. That way, if you already implemented the buttons as shown in the [Mobile touch controls](/en-US/docs/Games/Techniques/Control_mechanisms/Mobile_touch) article, it will work out of the box on the desktop too: ```js -const buttonEnclave = this.add.button(10, 10, 'logo-enclave', this.clickEnclave, this); +const buttonEnclave = this.add.button( + 10, + 10, + "logo-enclave", + this.clickEnclave, + this +); ``` The button will be placed ten pixels from the top left corner of the screen, use the `logo-enclave` image, and will execute the `clickEnclave()` function when clicked. We can assign actions directly to the buttons: ```js -this.buttonShoot = this.add.button(this.world.width * 0.5, 0, 'button-alpha', null, this); +this.buttonShoot = this.add.button( + this.world.width * 0.5, + 0, + "button-alpha", + null, + this +); this.buttonShoot.onInputDown.add(this.shootingPressed, this); this.buttonShoot.onInputUp.add(this.shootingReleased, this); ``` @@ -238,11 +251,11 @@ We've implemented the controls, and now we should inform the player about their ```js if (this.game.device.desktop) { - moveText = 'Arrow keys or WASD to move'; - shootText = 'X or Space to shoot'; + moveText = "Arrow keys or WASD to move"; + shootText = "X or Space to shoot"; } else { - moveText = 'Tap and hold to move'; - shootText = 'Tap to shoot'; + moveText = "Tap and hold to move"; + shootText = "Tap to shoot"; } ``` @@ -253,8 +266,8 @@ If the game is running on desktop, the cursor and W A { - console.log(event.keyCode); -}, true); +window.addEventListener( + "keydown", + (event) => { + console.log(event.keyCode); + }, + true +); ``` Every key pressed on the remote will show its key code in the console. You can also check this handy cheat sheet seen below if you're working with Panasonic TVs running Firefox OS: @@ -49,19 +54,23 @@ Every key pressed on the remote will show its key code in the console. You can a You can add moving between states, starting a new game, controlling the ship and blowing stuff up, pausing and restarting the game. All that is needed is checking for key presses: ```js -window.addEventListener("keydown", (event) => { - switch(event.keyCode) { - case 8: { - // Pause the game - break; - } - case 588: { - // Detonate bomb - break; +window.addEventListener( + "keydown", + (event) => { + switch (event.keyCode) { + case 8: { + // Pause the game + break; + } + case 588: { + // Detonate bomb + break; + } + // … } - // … - } -}, true); + }, + true +); ``` You can see it in action by watching [this video](https://www.youtube.com/watch?v=Bh11sP0bcTY). @@ -96,11 +105,12 @@ Leap.loop({ horizontalDegree = Math.round(hand.roll() * toDegrees); verticalDegree = Math.round(hand.pitch() * toDegrees); grabStrength = hand.grabStrength; - output.innerHTML = `Leap Motion:
    ` - + ` roll: ${horizontalDegree}°
    ` - + ` pitch: ${verticalDegree}°
    ` - + ` strength: ${grabStrength}`; - } + output.innerHTML = + `Leap Motion:
    ` + + ` roll: ${horizontalDegree}°
    ` + + ` pitch: ${verticalDegree}°
    ` + + ` strength: ${grabStrength}`; + }, }); ``` @@ -123,7 +133,7 @@ function draw() { playerY -= 5; } if (grabStrength === 1) { - alert('BOOM!'); + alert("BOOM!"); } ctx.drawImage(img, playerX, playerY); @@ -168,19 +178,19 @@ Check out the [banana piano video](https://www.youtube.com/watch?v=_DWQ6ce2Ags), There's even a [Cylon.js-supported Makey Button functionality](https://cylonjs.com/documentation/drivers/makey-button/) inspired by the MaKey MaKey board, so you can use the popular Cylon robotics framework for your experiments with Arduino or Raspberry Pi. Connecting the boards and using them may look like this: ```js -const Cylon = require('cylon'); +const Cylon = require("cylon"); Cylon.robot({ connections: { - arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' } + arduino: { adaptor: "firmata", port: "/dev/ttyACM0" }, }, devices: { - makey: { driver: 'makey-button', pin: 2 } + makey: { driver: "makey-button", pin: 2 }, }, work(my) { - my.makey.on('push', () => { + my.makey.on("push", () => { console.log("Button pushed!"); }); - } + }, }).start(); ``` diff --git a/files/en-us/games/techniques/controls_gamepad_api/index.md b/files/en-us/games/techniques/controls_gamepad_api/index.md index 902d37b1625aa01..4115dce8bbb6369 100644 --- a/files/en-us/games/techniques/controls_gamepad_api/index.md +++ b/files/en-us/games/techniques/controls_gamepad_api/index.md @@ -9,6 +9,7 @@ tags: - JavaScript - controllers --- + {{GamesSidebar}} This article looks at implementing an effective, cross-browser control system for web games using the Gamepad API, allowing you to control your web games using console game controllers. It features a case study game — Hungry Fridge, created by [Enclave Games](https://enclavegames.com/). @@ -58,7 +59,7 @@ const gamepadAPI = { buttons: [], buttonsCache: [], buttonsStatus: [], - axesStatus: [] + axesStatus: [], }; ``` @@ -198,10 +199,10 @@ There are two types of action to consider for a button: a single press and a hol ```js if (gamepadAPI.turbo) { - if (gamepadAPI.buttonPressed('A', 'hold')) { + if (gamepadAPI.buttonPressed("A", "hold")) { this.turbo_fire(); } - if (gamepadAPI.buttonPressed('B')) { + if (gamepadAPI.buttonPressed("B")) { this.managePause(); } } @@ -239,7 +240,7 @@ The mapping type is now an enumerable object instead of a string: ```ts enum GamepadMappingType { "", - "standard" + "standard", } ``` diff --git a/files/en-us/games/techniques/crisp_pixel_art_look/index.md b/files/en-us/games/techniques/crisp_pixel_art_look/index.md index 47dabf5c673f04d..4988683b4b410b9 100644 --- a/files/en-us/games/techniques/crisp_pixel_art_look/index.md +++ b/files/en-us/games/techniques/crisp_pixel_art_look/index.md @@ -12,6 +12,7 @@ tags: - image-rendering - pixel --- + {{GamesSidebar}} This article discusses a useful technique for giving your canvas/WebGL games a crisp pixel art look, even on high definition monitors. @@ -83,15 +84,15 @@ And some JavaScript to set up the canvas and load the image: ```js // Get canvas context -const ctx = document.getElementById('game').getContext('2d'); +const ctx = document.getElementById("game").getContext("2d"); // Load image const image = new Image(); image.onload = () => { // Draw the image into the canvas ctx.drawImage(image, 0, 0); -} -image.src = 'cat.png'; +}; +image.src = "cat.png"; ``` This code used together produces the following result: diff --git a/files/en-us/games/techniques/efficient_animation_for_web_games/index.md b/files/en-us/games/techniques/efficient_animation_for_web_games/index.md index 30f8f72a74e4406..68d3e8d36e28c82 100644 --- a/files/en-us/games/techniques/efficient_animation_for_web_games/index.md +++ b/files/en-us/games/techniques/efficient_animation_for_web_games/index.md @@ -6,6 +6,7 @@ tags: - Games - JavaScript --- + {{GamesSidebar}} This article covers techniques and advice for creating efficient animation for web games, with a slant towards supporting lower end devices such as mobile phones. We touch on [CSS transitions](/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions) and [CSS animations](/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations), and JavaScript loops involving {{ domxref("window.requestAnimationFrame") }}. @@ -82,12 +83,11 @@ How this conclusion was reached, however, is more important than the conclusion To help combat poor animation performance, Chris Lord wrote [Animator.js](https://gitlab.com/Cwiiis/animator-js/blob/master/Animator.js), a simple, easy-to-use animation library, heavily influenced by various parts of [Clutter](https://blogs.gnome.org/clutter/), but with a focus on avoiding scope-creep. It does one thing, and it does it well. Animator.js is a fire-and-forget style animation library, designed to be used with games, or other situations where you need many, synchronized, custom animations. It includes a handful of built-in tweening functions, the facility to add your own, and helper functions for animating object properties. Puzzowl uses it to drive all the drawing updates and transitions, by overriding its `requestAnimationFrame` function with a custom version that makes the request, and appending the game's drawing function onto the end of the callback like so: ```js -animator.requestAnimationFrame = - (callback) => { - requestAnimationFrame((t) => { - callback(t); - redraw(); - }); +animator.requestAnimationFrame = (callback) => { + requestAnimationFrame((t) => { + callback(t); + redraw(); + }); }; ``` diff --git a/files/en-us/games/techniques/index.md b/files/en-us/games/techniques/index.md index 5b2d02accf8ad6a..21be9cdc7b8aac0 100644 --- a/files/en-us/games/techniques/index.md +++ b/files/en-us/games/techniques/index.md @@ -5,6 +5,7 @@ tags: - Games - Guide --- + {{GamesSidebar}} This page lists essential core techniques for anyone wanting to develop games using open web technologies. diff --git a/files/en-us/games/techniques/tilemaps/index.md b/files/en-us/games/techniques/tilemaps/index.md index 2ca9562aad1e4d5..f5b07abb4c726d3 100644 --- a/files/en-us/games/techniques/tilemaps/index.md +++ b/files/en-us/games/techniques/tilemaps/index.md @@ -11,6 +11,7 @@ tags: - tilemap - tiles --- + {{GamesSidebar}} Tilemaps are a very popular technique in 2D game development, consisting of building the game world or level map out of small, regular-shaped images called **tiles**. This results in performance and memory usage gains — big image files containing entire level maps are not needed, as they are constructed by small images or image fragments multiple times. This set of articles covers the basics of creating tile maps using [JavaScript](/en-US/docs/Web/JavaScript) and [Canvas](/en-US/docs/Web/API/Canvas_API) (although the same high level techniques could be used in any programming language.) @@ -79,11 +80,11 @@ Here are examples showing how to translate from world coordinates to screen coor // these functions assume that the camera points to the top left corner function worldToScreen(x, y) { - return {x: x - camera.x, y: y - camera.y}; + return { x: x - camera.x, y: y - camera.y }; } -function screenToWorld(x,y) { - return {x: x + camera.x, y: y + camera.y}; +function screenToWorld(x, y) { + return { x: x + camera.x, y: y + camera.y }; } ``` @@ -125,7 +126,7 @@ One way consists of [drawing the section that will be visible off-canvas](https: A caveat of that approach is that when there _is_ a scrolling, that technique is not very efficient. A better way would be to create a canvas that is 2x2 tiles bigger than the visible area, so there is one tile of "bleeding" around the edges. That means that the map only needs to be redrawn on the canvas when the scrolling has advanced one full tile — instead of every frame — while scrolling. -In fast games that might still not be enough. An alternative method would be to split the tilemap into big sections (like a full map split into 10 x 10 chunks of tiles), pre-render each one off-canvas and then treat each rendered section as a "big tile" in combination with one of the algorithms discussed above. +In fast games that might still not be enough. An alternative method would be to split the tilemap into big sections (like a full map split into 10 x 10 chunks of tiles), pre-render each one off-canvas and then treat each rendered section as a "big tile" in combination with one of the algorithms discussed above. ## See also diff --git a/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__scrolling_maps/index.md b/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__scrolling_maps/index.md index ddb1155ef2b54e4..7b3136662f2b357 100644 --- a/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__scrolling_maps/index.md +++ b/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__scrolling_maps/index.md @@ -1,5 +1,5 @@ --- -title: 'Square tilemaps implementation: Scrolling maps' +title: "Square tilemaps implementation: Scrolling maps" slug: Games/Techniques/Tilemaps/Square_tilemaps_implementation:_Scrolling_maps tags: - Canvas @@ -11,6 +11,7 @@ tags: - tilemap - tiles --- + {{GamesSidebar}} This article covers how to implement scrolling square tilemaps using the [Canvas API](/en-US/docs/Web/API/Canvas_API). @@ -61,14 +62,15 @@ for (let c = startCol; c <= endCol; c++) { const tile = map.getTile(c, r); const x = (c - startCol) * map.tsize + offsetX; const y = (r - startRow) * map.tsize + offsetY; - if (tile !== 0) { // 0 => empty tile + if (tile !== 0) { + // 0 => empty tile this.ctx.drawImage( this.tileAtlas, // image (tile - 1) * map.tsize, // source x 0, // source y map.tsize, // source width map.tsize, // source height - Math.round(x), // target x + Math.round(x), // target x Math.round(y), // target y map.tsize, // target width map.tsize // target height diff --git a/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__static_maps/index.md b/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__static_maps/index.md index 01ba059870bcfd3..86d4ed496023326 100644 --- a/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__static_maps/index.md +++ b/files/en-us/games/techniques/tilemaps/square_tilemaps_implementation_colon__static_maps/index.md @@ -1,5 +1,5 @@ --- -title: 'Square tilemaps implementation: Static maps' +title: "Square tilemaps implementation: Static maps" slug: Games/Techniques/Tilemaps/Square_tilemaps_implementation:_Static_maps tags: - Canvas @@ -12,6 +12,7 @@ tags: - tilemaps - tiles --- + {{GamesSidebar}} This article covers how to implement static square tilemaps using the [Canvas API](/en-US/docs/Web/API/Canvas_API). @@ -60,18 +61,13 @@ const map = { rows: 8, tsize: 64, tiles: [ - 1, 3, 3, 3, 1, 1, 3, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 1, 1, 1, - 1, 1, 1, 1, 2, 1, 1, 1, - 1, 1, 1, 0, 0, 1, 1, 1 + 1, 3, 3, 3, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, ], getTile(col, row) { - return this.tiles[row * map.cols + col] - } + return this.tiles[row * map.cols + col]; + }, }; ``` @@ -87,7 +83,8 @@ We can render the map by iterating over its columns and rows. This snippet assum for (let c = 0; c < map.cols; c++) { for (let r = 0; r < map.rows; r++) { const tile = map.getTile(c, r); - if (tile !== 0) { // 0 => empty tile + if (tile !== 0) { + // 0 => empty tile context.drawImage( tileAtlas, // image (tile - 1) * map.tsize, // source x diff --git a/files/en-us/games/techniques/webrtc_data_channels/index.md b/files/en-us/games/techniques/webrtc_data_channels/index.md index dffd7c659b69e29..f6616f35459cc31 100644 --- a/files/en-us/games/techniques/webrtc_data_channels/index.md +++ b/files/en-us/games/techniques/webrtc_data_channels/index.md @@ -10,6 +10,7 @@ tags: - WebRTC - data channels --- + {{GamesSidebar}} The [WebRTC](/en-US/docs/Web/API/WebRTC_API) (Web Real-Time Communications) API is primarily known for its support for audio and video communications; however, it also offers peer-to-peer data channels. This article explains more about this, and shows you how to use libraries to implement data channels in your game. diff --git a/files/en-us/games/tools/asm.js/index.md b/files/en-us/games/tools/asm.js/index.md index 5d1e6ae8dcbdde8..2a8c1c8e9eff946 100644 --- a/files/en-us/games/tools/asm.js/index.md +++ b/files/en-us/games/tools/asm.js/index.md @@ -6,6 +6,7 @@ tags: - JavaScript - asm.js --- + {{Deprecated_header}}{{GamesSidebar}} [Asm.js](http://asmjs.org/) is a specification defining a subset of JavaScript that is highly optimizable. This article looks at exactly what is permitted in the asm.js subset, what improvements it confers, where and how you can make use of it, and further resources and examples. @@ -22,4 +23,4 @@ Additionally, if an engine chooses to specially recognize asm.js code, there eve ## asm.js language summary -asm.js is an intermediate programming language. asm.js has a very predictable performance rate because it is limited to an extremely restricted subset of JavaScript that provides only strictly-typed integers, floats, arithmetic, function calls, and heap accesses. The performance characteristics are closer to native code than that of standard JavaScript. Using a subset of JavaScript asm.js is already supported by major web browsers. Since asm.js runs in a browser it depends heavily on the browser and the hardware. +asm.js is an intermediate programming language. asm.js has a very predictable performance rate because it is limited to an extremely restricted subset of JavaScript that provides only strictly-typed integers, floats, arithmetic, function calls, and heap accesses. The performance characteristics are closer to native code than that of standard JavaScript. Using a subset of JavaScript asm.js is already supported by major web browsers. Since asm.js runs in a browser it depends heavily on the browser and the hardware. diff --git a/files/en-us/games/tools/index.md b/files/en-us/games/tools/index.md index 98d60da39ea9b03..3d0f9ec615c4110 100644 --- a/files/en-us/games/tools/index.md +++ b/files/en-us/games/tools/index.md @@ -7,6 +7,7 @@ tags: - Guide - JavaScript --- + {{GamesSidebar}} On this page you can find links to our game development tools articles, which eventually aims to cover frameworks, compilers, and debugging tools. diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md index 7866787e8301d84..821b7d123c1fae9 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md @@ -12,6 +12,7 @@ tags: - Tutorial - tween --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Extra_lives", "Games/Workflows/2D_Breakout_game_Phaser/Buttons")}} @@ -29,7 +30,7 @@ First of all, [grab the spritesheet from GitHub](https://github.com/end3r/Gamede Next, we will load the spritesheet — put the following line at the bottom of your `preload()` function: ```js -game.load.spritesheet('ball', 'img/wobble.png', 20, 20); +game.load.spritesheet("ball", "img/wobble.png", 20, 20); ``` Instead of loading a single image of the ball we can load the whole spritesheet — a collection of different images. We will show the sprites sequentially to create the illusion of animation. The `spritesheet()` method's two extra parameters determine the width and height of each single frame in the given spritesheet file, indicating to the program how to chop it up to get the individual frames. @@ -39,8 +40,8 @@ Instead of loading a single image of the ball we can load the whole spritesheet Next up, go into your create() function, find the line that loads the ball sprite, and below it put the call to `animations.add()` seen below: ```js -ball = game.add.sprite(50, 250, 'ball'); -ball.animations.add('wobble', [0, 1, 0, 2, 0, 1, 0, 2, 0], 24); +ball = game.add.sprite(50, 250, "ball"); +ball.animations.add("wobble", [0, 1, 0, 2, 0, 1, 0, 2, 0], 24); ``` To add an animation to the object we use the `animations.add()` method, which contains the following parameters @@ -65,7 +66,7 @@ Then we can create the `ballHitPaddle()` function (having `ball` and `paddle` as ```js function ballHitPaddle(ball, paddle) { - ball.animations.play('wobble'); + ball.animations.play("wobble"); } ``` @@ -96,7 +97,9 @@ Let's walk through this so you can see what's happening here: That's the expanded version of the tween definition, but we can also use the shorthand syntax: ```js -game.add.tween(brick.scale).to({ x: 2, y: 2} , 500, Phaser.Easing.Elastic.Out, true, 100); +game.add + .tween(brick.scale) + .to({ x: 2, y: 2 }, 500, Phaser.Easing.Elastic.Out, true, 100); ``` This tween will double the brick's scale in half a second using Elastic easing, will start automatically, and have a delay of 100 milliseconds. diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md index 0bc2a08a39068ee..3ced95d11660b61 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - bouncing --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Physics", "Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md index 227548348d58c48..e6eddbaeadfc29f 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md @@ -10,6 +10,7 @@ tags: - Phaser - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Game_over", "Games/Workflows/2D_Breakout_game_Phaser/Collision_detection")}} @@ -37,7 +38,7 @@ Next, let's load the image of the brick — add the following `load.image()` cal ```js function preload() { // … - game.load.image('brick', 'img/brick.png'); + game.load.image("brick", "img/brick.png"); } ``` @@ -54,7 +55,7 @@ function create() { } ``` -Now onto the function itself. Add the `initBricks()` function at the end of our games code, just before the closing \ tag, as shown below. To begin with we've included the `brickInfo` object, as this will come in handy very soon: +Now onto the function itself. Add the `initBricks()` function at the end of our games code, just before the closing \ tag, as shown below. To begin with we've included the `brickInfo` object, as this will come in handy very soon: ```js function initBricks() { @@ -63,13 +64,13 @@ function initBricks() { height: 20, count: { row: 3, - col: 7 + col: 7, }, offset: { top: 50, - left: 60 + left: 60, }, - padding: 10 + padding: 10, }; } ``` @@ -99,7 +100,7 @@ for (let c = 0; c < brickInfo.count.col; c++) { for (let r = 0; r < brickInfo.count.row; r++) { let brickX = 0; let brickY = 0; - newBrick = game.add.sprite(brickX, brickY, 'brick'); + newBrick = game.add.sprite(brickX, brickY, "brick"); game.physics.enable(newBrick, Phaser.Physics.ARCADE); newBrick.body.immovable = true; newBrick.anchor.set(0.5); @@ -113,8 +114,10 @@ Here we're looping through the rows and columns to create the new bricks and pla The problem currently is that we're painting all the bricks in one place, at coordinates (0,0). What we need to do is draw each brick at its own x and y position. Update the `brickX` and `brickY` lines as follows: ```js -const brickX = c * (brickInfo.width + brickInfo.padding) + brickInfo.offset.left; -const brickY = r * (brickInfo.height + brickInfo.padding) + brickInfo.offset.top; +const brickX = + c * (brickInfo.width + brickInfo.padding) + brickInfo.offset.left; +const brickY = + r * (brickInfo.height + brickInfo.padding) + brickInfo.offset.top; ``` Each `brickX` position is worked out as `brickInfo.width` plus `brickInfo.padding`, multiplied by the column number, `c`, plus the `brickInfo.offset.left`; the logic for the `brickY` is identical except that it uses the values for row number, `r`, `brickInfo.height`, and `brickInfo.offset.top`. Now every single brick can be placed in its correct place, with padding between each brick, and drawn at an offset from the left and top Canvas edges. @@ -130,20 +133,22 @@ function initBricks() { height: 20, count: { row: 3, - col: 7 + col: 7, }, offset: { top: 50, - left: 60 + left: 60, }, - padding: 10 - } + padding: 10, + }; bricks = game.add.group(); for (let c = 0; c < brickInfo.count.col; c++) { for (let r = 0; r < brickInfo.count.row; r++) { - const brickX = c * (brickInfo.width+brickInfo.padding) + brickInfo.offset.left; - const brickY = r * (brickInfo.height+brickInfo.padding) + brickInfo.offset.top; - newBrick = game.add.sprite(brickX, brickY, 'brick'); + const brickX = + c * (brickInfo.width + brickInfo.padding) + brickInfo.offset.left; + const brickY = + r * (brickInfo.height + brickInfo.padding) + brickInfo.offset.top; + newBrick = game.add.sprite(brickX, brickY, "brick"); game.physics.enable(newBrick, Phaser.Physics.ARCADE); newBrick.body.immovable = true; newBrick.anchor.set(0.5); diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/buttons/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/buttons/index.md index ade0305370b9703..c8e78e723e266b5 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/buttons/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/buttons/index.md @@ -11,6 +11,7 @@ tags: - Phaser - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens", "Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay")}} @@ -33,7 +34,7 @@ let startButton; We can load the button spritesheet the same way we loaded the ball's wobble animation. Add the following to the bottom of the `preload()` function: ```js -game.load.spritesheet('button', 'img/button.png', 120, 40); +game.load.spritesheet("button", "img/button.png", 120, 40); ``` A single button frame is 120 pixels wide and 40 pixels high. @@ -48,7 +49,7 @@ Adding the new button to the game is done by using the `add.button` method. Add startButton = game.add.button( game.world.width * 0.5, game.world.height * 0.5, - 'button', + "button", startGame, this, 1, diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md index a8a1c16badda7a5..52c3e7664b5c8be 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - collision detection --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_Phaser/The_score")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md index 9404ba8395c32c2..6e1830c035c1622 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - lives --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}} @@ -36,9 +37,17 @@ These respectively will store the number of lives, the text label that displays Defining the texts look like something we already did in [the score](/en-US/docs/Games/Tutorials/2D_breakout_game_Phaser/The_score) lesson. Add the following lines below the existing `scoreText` definition inside your `create()` function: ```js -livesText = game.add.text(game.world.width - 5, 5, `Lives: ${lives}`, { font: '18px Arial', fill: '#0095DD' }); +livesText = game.add.text(game.world.width - 5, 5, `Lives: ${lives}`, { + font: "18px Arial", + fill: "#0095DD", +}); livesText.anchor.set(1, 0); -lifeLostText = game.add.text(game.world.width * 0.5, game.world.height * 0.5, 'Life lost, click to continue', { font: '18px Arial', fill: '#0095DD' }); +lifeLostText = game.add.text( + game.world.width * 0.5, + game.world.height * 0.5, + "Life lost, click to continue", + { font: "18px Arial", fill: "#0095DD" } +); lifeLostText.anchor.set(0.5); lifeLostText.visible = false; ``` @@ -52,16 +61,26 @@ The `lifeLostText` will be shown only when the life is lost, so its visibility i As you probably noticed we're using the same styling for all three texts: `scoreText`, `livesText` and `lifeLostText`. If we ever want to change the font size or color we will have to do it in multiple places. To make it easier for us to maintain in the future we can create a separate variable that will hold our styling, let's call it `textStyle` and place it before the text definitions: ```js -textStyle = { font: '18px Arial', fill: '#0095DD' }; +textStyle = { font: "18px Arial", fill: "#0095DD" }; ``` We can now use this variable when styling our text labels — update your code so that the multiple instances of the text styling are replaced with the variable: ```js -scoreText = game.add.text(5, 5, 'Points: 0', textStyle); -livesText = game.add.text(game.world.width - 5, 5, `Lives: ${lives}`, textStyle); -livesText.anchor.set(1,0); -lifeLostText = game.add.text(game.world.width * 0.5, game.world.height * 0.5, 'Life lost, click to continue', textStyle); +scoreText = game.add.text(5, 5, "Points: 0", textStyle); +livesText = game.add.text( + game.world.width - 5, + 5, + `Lives: ${lives}`, + textStyle +); +livesText.anchor.set(1, 0); +lifeLostText = game.add.text( + game.world.width * 0.5, + game.world.height * 0.5, + "Life lost, click to continue", + textStyle +); lifeLostText.anchor.set(0.5); lifeLostText.visible = false; ``` @@ -74,7 +93,7 @@ To implement lives in our game, let's first change the ball's function bound to ```js ball.events.onOutOfBounds.add(() => { - alert('Game over!'); + alert("Game over!"); location.reload(); }, this); ``` @@ -100,7 +119,7 @@ function ballLeaveScreen() { ball.body.velocity.set(150, -150); }, this); } else { - alert('You lost, game over!'); + alert("You lost, game over!"); location.reload(); } } diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/game_over/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/game_over/index.md index 839f0242f7a8d14..a09daac55de159e 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/game_over/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/game_over/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - game over --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls", "Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field")}} @@ -32,7 +33,7 @@ This will make the three walls (top, left and right) bounce the ball back, but t ```js ball.checkWorldBounds = true; ball.events.onOutOfBounds.add(() => { - alert('Game over!'); + alert("Game over!"); location.reload(); }, this); ``` diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/index.md index 8d54c08a3617161..05abc90e7c13fd1 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/index.md @@ -10,6 +10,7 @@ tags: - Phaser - Tutorial --- + {{GamesSidebar}} {{Next("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md index 28922955df110cf..855d4c6ccb38e8c 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md @@ -11,6 +11,7 @@ tags: - Phaser - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser", "Games/Workflows/2D_Breakout_game_Phaser/Scaling")}} @@ -26,24 +27,29 @@ The HTML document structure is quite simple, as the game will be rendered entire ```html - + Gamedev Phaser Workshop - lesson 01: Initialize the framework - + - - - - + + + + ``` diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md index 4e581d454e3cfd3..617c6876d87a863 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md @@ -12,6 +12,7 @@ tags: - Sprites - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Scaling", "Games/Workflows/2D_Breakout_game_Phaser/Move the ball")}} @@ -37,7 +38,7 @@ Loading images and printing them on our canvas is a lot easier using Phaser than ```js function preload() { // … - game.load.image('ball', 'img/ball.png'); + game.load.image("ball", "img/ball.png"); } ``` @@ -45,11 +46,11 @@ The first parameter we want to give the asset is the name that will be used acro Of course, to load the image, it must be available in our code directory. [Grab the ball image from GitHub](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/ball.png), and save it inside an `/img` directory in the same place as your `index.html` file. -Now, to show it on the screen we will use another Phaser method called `add.sprite()`; add the following new code line inside the `create()` function as shown: +Now, to show it on the screen we will use another Phaser method called `add.sprite()`; add the following new code line inside the `create()` function as shown: ```js function create() { - ball = game.add.sprite(50, 50, 'ball'); + ball = game.add.sprite(50, 50, "ball"); } ``` diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md index 10e77e98359eca3..e4c48b2b532366a 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - moving --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Workflows/2D_Breakout_game_Phaser/Physics")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/physics/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/physics/index.md index 933dcff919a0e08..6bdcd289fb8dc95 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/physics/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/physics/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - physics --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball", "Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls")}} @@ -65,19 +66,18 @@ function preload() { game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; game.scale.pageAlignHorizontally = true; game.scale.pageAlignVertically = true; - game.stage.backgroundColor = '#eee'; - game.load.image('ball', 'img/ball.png'); + game.stage.backgroundColor = "#eee"; + game.load.image("ball", "img/ball.png"); } function create() { game.physics.startSystem(Phaser.Physics.ARCADE); - ball = game.add.sprite(50, 50, 'ball'); + ball = game.add.sprite(50, 50, "ball"); game.physics.enable(ball, Phaser.Physics.ARCADE); ball.body.velocity.set(150, 150); } -function update() { -} +function update() {} ``` Try reloading `index.html` again — The ball should now be moving constantly in the given direction. At the moment, the physics engine has gravity and friction set to zero. Adding gravity would result in the ball falling down while friction would eventually stop the ball. diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md index a0829514bd8d2b4..27a8e65189f3acb 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md @@ -10,6 +10,7 @@ tags: - Phaser - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_Phaser/Game_over")}} @@ -35,8 +36,8 @@ Then, in the `preload` function, load the `paddle` image by adding the following ```js function preload() { // … - game.load.image('ball', 'img/ball.png'); - game.load.image('paddle', 'img/paddle.png'); + game.load.image("ball", "img/ball.png"); + game.load.image("paddle", "img/paddle.png"); } ``` @@ -49,7 +50,11 @@ Just so we don't forget, at this point you should grab the [paddle graphic](http Next up, we will initialize our paddle by adding the following `add.sprite()` call inside the `create()` function — add it right at the bottom: ```js -paddle = game.add.sprite(game.world.width*0.5, game.world.height-5, 'paddle'); +paddle = game.add.sprite( + game.world.width * 0.5, + game.world.height - 5, + "paddle" +); ``` We can use the `world.width` and `world.height` values to position the paddle exactly where we want it: `game.world.width*0.5` will be right in the middle of the screen. In our case the world is the same as the Canvas, but for other types of games, like side-scrollers for example, the world will be bigger, and you can tinker with it to create interesting effects. @@ -57,7 +62,7 @@ We can use the `world.width` and `world.height` values to position the paddle ex As you'll notice if you reload your `index.html` at this point, the paddle is currently not exactly in the middle. Why? Because the anchor from which the position is calculated always starts from the top left edge of the object. We can change that to have the anchor in the middle of the paddle's width and at the bottom of its height, so it's easier to position it against the bottom edge. Add the following line below the previous new one: ```js -paddle.anchor.set(0.5,1); +paddle.anchor.set(0.5, 1); ``` The paddle is now positioned right where we want it to be. Now, to make it collide with the ball we have to enable physics for the paddle. Continue by adding the following new line, again at the bottom of the `create()` function: @@ -106,7 +111,7 @@ If you haven't already done so, reload your `index.html` and try it out! We have the paddle working as expected, so let's position the ball on it. It's very similar to positioning the paddle — we need to have it placed in the middle of the screen horizontally and at the bottom vertically with a little offset from the bottom. To place it exactly as we want it we will set the anchor to the exact middle of the ball. Find the existing `ball = game.add.sprite()` line, and replace it with the following two lines: ```js -ball = game.add.sprite(game.world.width * 0.5, game.world.height - 25, 'ball'); +ball = game.add.sprite(game.world.width * 0.5, game.world.height - 25, "ball"); ball.anchor.set(0.5); ``` diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md index 2c99a25b582c2a9..59d9fe511f9edb7 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md @@ -10,6 +10,7 @@ tags: - Phaser - Tutorial --- + {{GamesSidebar}} {{Previous("Games/Workflows/2D_Breakout_game_Phaser/Buttons")}} @@ -24,7 +25,7 @@ We can change the ball's velocity depending on the exact spot it hits the paddle ```js function ballHitPaddle(ball, paddle) { - ball.animations.play('wobble'); + ball.animations.play("wobble"); ball.body.velocity.x = -5 * (paddle.x - ball.x); } ``` diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/scaling/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/scaling/index.md index 39bae4f118123c4..84d5501f00a1cbb 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/scaling/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/scaling/index.md @@ -10,6 +10,7 @@ tags: - Phaser - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework", "Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen")}} @@ -45,7 +46,7 @@ The other two lines of code in the `preload()` function are responsible for alig We can also add a custom background color to our canvas, so it won't stay black. The `stage` object has a `backgroundColor` property for this purpose, which we can set using CSS color definition syntax. Add the following line below the other three you added earlier: ```js -game.stage.backgroundColor = '#eee'; +game.stage.backgroundColor = "#eee"; ``` ## Compare your code diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/the_score/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/the_score/index.md index e8fd14c2a2e8edb..ac34c351f369b5d 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/the_score/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/the_score/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - scoring --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Collision_detection", "Games/Workflows/2D_Breakout_game_Phaser/Win_the_game")}} @@ -36,7 +37,10 @@ let score = 0; Now add this line at the end of the `create()` function: ```js -scoreText = game.add.text(5, 5, 'Points: 0', { font: '18px Arial', fill: '#0095DD' }); +scoreText = game.add.text(5, 5, "Points: 0", { + font: "18px Arial", + fill: "#0095DD", +}); ``` The `text()` method can take four parameters: diff --git a/files/en-us/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md b/files/en-us/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md index 2e81cbf8040e58c..a51b1a6a74380fb 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - winning --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/The_score", "Games/Workflows/2D_Breakout_game_Phaser/Extra_lives")}} @@ -36,7 +37,7 @@ function ballHitBrick(ball, brick) { } } if (count_alive === 0) { - alert('You won the game, congratulations!'); + alert("You won the game, congratulations!"); location.reload(); } } diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md index f2c7a32b6ea5560..a894b62663f454e 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md @@ -12,6 +12,7 @@ tags: - collision - detection --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}} @@ -93,10 +94,10 @@ Test your code at this point, and you will be impressed — now we have a ball t This is because we're calculating the collision point of the wall and the center of the ball, while we should be doing it for its circumference. The ball should bounce right after if touches the wall, not when it's already halfway in the wall, so let's adjust our statements a bit to include that. Update the last code you added to this: ```js -if (x + dx > canvas.width-ballRadius || x + dx < ballRadius) { +if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) { dx = -dx; } -if (y + dy > canvas.height-ballRadius || y + dy < ballRadius) { +if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) { dy = -dy; } ``` diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md index 5f87fb673b3fb99..d82457a0ac40feb 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md @@ -9,6 +9,7 @@ tags: - JavaScript - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}} @@ -106,7 +107,7 @@ drawBricks(); ## Compare your code -At this point, the game has got a little more interesting again : +At this point, the game has got a little more interesting again : {{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/Lu3vtejz/","","395")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md index 265d041a2ea85ab..1d5ba8faddde987 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md @@ -10,6 +10,7 @@ tags: - collision - detection --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}} @@ -27,7 +28,7 @@ To kick this all off we want to create a collision detection function that will ```js function collisionDetection() { for (let c = 0; c < brickColumnCount; c++) { - for(let r = 0; r < brickRowCount; r++) { + for (let r = 0; r < brickRowCount; r++) { const b = bricks[c][r]; // calculations } @@ -49,7 +50,7 @@ function collisionDetection() { for (let c = 0; c < brickColumnCount; c++) { for (let r = 0; r < brickRowCount; r++) { const b = bricks[c][r]; - if (x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) { + if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) { dy = -dy; } } @@ -105,7 +106,12 @@ function collisionDetection() { for (let r = 0; r < brickRowCount; r++) { const b = bricks[c][r]; if (b.status === 1) { - if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) { + if ( + x > b.x && + x < b.x + brickWidth && + y > b.y && + y < b.y + brickHeight + ) { dy = -dy; b.status = 0; } diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md index fd757e951e98ae7..0a4a9deb76f1bb5 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md @@ -11,6 +11,7 @@ tags: - JavaScript - Tutorial --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}} @@ -26,23 +27,28 @@ The HTML document structure is quite simple, as the game will be rendered entire ```html - - - Gamedev Canvas Workshop - - - - - - - - - + + + Gamedev Canvas Workshop + + + + + + + ``` @@ -75,7 +81,7 @@ We're not limited to rectangles — here's a piece of code for printing out a gr ```js ctx.beginPath(); -ctx.arc(240, 160, 20, 0, Math.PI*2, false); +ctx.arc(240, 160, 20, 0, Math.PI * 2, false); ctx.fillStyle = "green"; ctx.fill(); ctx.closePath(); diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md index 5c209455d8a6c0f..46f5e32ecdfd7ab 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md @@ -10,6 +10,7 @@ tags: - lives - requestAnimationFrame --- + {{GamesSidebar}} {{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md index 0a2dcd2427801af..566fae715a8023d 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md @@ -10,6 +10,7 @@ tags: - Tutorial - game over --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field")}} @@ -23,11 +24,11 @@ It's fun to watch the ball bouncing off the walls and be able to move the paddle Let's try to implement game over in our game. Here's the piece of code from the third lesson where we made the ball bounce off the walls: ```js -if (x + dx > canvas.width-ballRadius || x + dx < ballRadius) { +if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) { dx = -dx; } -if (y + dy > canvas.height-ballRadius || y + dy < ballRadius) { +if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) { dy = -dy; } ``` @@ -51,7 +52,7 @@ Then replace the second if statement with the following: ```js if (y + dy < ballRadius) { dy = -dy; -} else if (y + dy > canvas.height-ballRadius) { +} else if (y + dy > canvas.height - ballRadius) { alert("GAME OVER"); document.location.reload(); clearInterval(interval); // Needed for Chrome to end game @@ -65,7 +66,7 @@ The last thing to do in this lesson is to create some kind of collision detectio ```js if (y + dy < ballRadius) { dy = -dy; -} else if (y + dy > canvas.height-ballRadius) { +} else if (y + dy > canvas.height - ballRadius) { if (x > paddleX && x < paddleX + paddleWidth) { dy = -dy; } else { diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/index.md index 2ac68c652328685..244aac73b24bec1 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/index.md @@ -9,6 +9,7 @@ tags: - JavaScript - Tutorial --- + {{GamesSidebar}} {{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md index 21f9ab77b09742a..4623c11d0bb1630 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md @@ -10,6 +10,7 @@ tags: - Tutorial - mouse --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}} @@ -34,7 +35,7 @@ We can update the paddle position based on the pointer coordinates — the follo function mouseMoveHandler(e) { const relativeX = e.clientX - canvas.offsetLeft; if (relativeX > 0 && relativeX < canvas.width) { - paddleX = relativeX - paddleWidth/2; + paddleX = relativeX - paddleWidth / 2; } } ``` diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md index 55560d100937b97..0b4410f92e1078e 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - movement --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}} diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md index 8d29265530e138a..3e1fe797990429c 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md @@ -11,6 +11,7 @@ tags: - Tutorial - keyboard --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over")}} @@ -86,7 +87,7 @@ function keyUpHandler(e) { When we press a key down, this information is stored in a variable. The relevant variable in each case is set to `true`. When the key is released, the variable is set back to `false`. -Both functions take an event as a parameter, represented by the `e` variable. From that you can get useful information: the `key` holds the information about the key that was pressed. Most browsers use `ArrowRight` and `ArrowLeft` for the left/right cursor keys, but we need to also include `Right` and `Left` checks to support IE/Edge browsers. If the left cursor is pressed, then the `leftPressed` variable is set to `true`, and when it is released, the `leftPressed` variable is set to `false`. The same pattern follows with the right cursor and the `rightPressed` variable. +Both functions take an event as a parameter, represented by the `e` variable. From that you can get useful information: the `key` holds the information about the key that was pressed. Most browsers use `ArrowRight` and `ArrowLeft` for the left/right cursor keys, but we need to also include `Right` and `Left` checks to support IE/Edge browsers. If the left cursor is pressed, then the `leftPressed` variable is set to `true`, and when it is released, the `leftPressed` variable is set to `false`. The same pattern follows with the right cursor and the `rightPressed` variable. ### The paddle moving logic diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md index bf1eda316f1e115..98111a25b964377 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md @@ -10,6 +10,7 @@ tags: - scoring - winning --- + {{GamesSidebar}} {{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}} @@ -46,7 +47,12 @@ function collisionDetection() { for (let r = 0; r < brickRowCount; r++) { const b = bricks[c][r]; if (b.status === 1) { - if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) { + if ( + x > b.x && + x < b.x + brickWidth && + y > b.y && + y < b.y + brickHeight + ) { dy = -dy; b.status = 0; score++; @@ -73,7 +79,12 @@ function collisionDetection() { for (let r = 0; r < brickRowCount; r++) { const b = bricks[c][r]; if (b.status === 1) { - if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) { + if ( + x > b.x && + x < b.x + brickWidth && + y > b.y && + y < b.y + brickHeight + ) { dy = -dy; b.status = 0; score++; diff --git a/files/en-us/games/tutorials/html5_gamedev_phaser_device_orientation/index.md b/files/en-us/games/tutorials/html5_gamedev_phaser_device_orientation/index.md index 96f62021fb01c12..56f3884d9e71661 100644 --- a/files/en-us/games/tutorials/html5_gamedev_phaser_device_orientation/index.md +++ b/files/en-us/games/tutorials/html5_gamedev_phaser_device_orientation/index.md @@ -9,6 +9,7 @@ tags: - Phaser - Vibration API --- + {{GamesSidebar}} In this tutorial we'll go through the process of building an HTML mobile game that uses the [Device Orientation](/en-US/docs/Web/Apps/Fundamentals/gather_and_modify_data/responding_to_device_orientation_changes) and [Vibration](/en-US/docs/Web/API/Vibration_API) **APIs** to enhance the gameplay and is built using the [Phaser](https://phaser.io/) framework. Basic JavaScript knowledge is recommended to get the most from this tutorial. @@ -42,43 +43,48 @@ We will be rendering our game on Canvas, but we won't do it manually — this wi ```html - + Cyber Orb demo - + - - - - + + + + ``` So far we have a simple HTML website with some basic content in the `` section: charset, title, CSS styling and the inclusion of the JavaScript files. The `` contains initialization of the Phaser framework and the definitions of the game states. ```js -const game = new Phaser.Game(320, 480, Phaser.CANVAS, 'game'); +const game = new Phaser.Game(320, 480, Phaser.CANVAS, "game"); ``` The line above will initialize the Phaser instance — the arguments are the width of the Canvas, height of the Canvas, rendering method (we're using `CANVAS`, but there are also `WEBGL` and `AUTO` options available) and the optional ID of the DOM container we want to put the Canvas in. If there's nothing specified in that last argument or the element is not found, the Canvas will be added to the \ tag. Without the framework, to add the Canvas element to the page, you would have to write something like this inside the \ tag: ```html - + ``` The important thing to remember is that the framework is setting up helpful methods to speed up a lot of things like image manipulation or assets management, which would be a lot harder to do manually. @@ -88,7 +94,7 @@ The important thing to remember is that the framework is setting up helpful meth Back to game states: the line below is adding a new state called `Boot` to the game: ```js -game.state.add('Boot', Ball.Boot); +game.state.add("Boot", Ball.Boot); ``` The first value is the name of the state and the second one is the object we want to assign to it. The `start` method is starting the given state and making it active. Let's see what the states are actually. @@ -104,21 +110,21 @@ The `Boot` state is the first one in the game. ```js const Ball = { _WIDTH: 320, - _HEIGHT: 480 + _HEIGHT: 480, }; Ball.Boot = function (game) {}; Ball.Boot.prototype = { preload() { - this.load.image('preloaderBg', 'img/loading-bg.png'); - this.load.image('preloaderBar', 'img/loading-bar.png'); + this.load.image("preloaderBg", "img/loading-bg.png"); + this.load.image("preloaderBar", "img/loading-bar.png"); }, create() { this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; this.game.scale.pageAlignHorizontally = true; this.game.scale.pageAlignVertically = true; - this.game.state.start('Preloader'); - } + this.game.state.start("Preloader"); + }, }; ``` @@ -129,22 +135,34 @@ The main `Ball` object is defined and we're adding two variables called `_WIDTH` The `Preloader` state takes care of loading all the assets: ```js -Ball.Preloader = function(game) {}; +Ball.Preloader = function (game) {}; Ball.Preloader.prototype = { preload() { - this.preloadBg = this.add.sprite((Ball._WIDTH - 297) * 0.5, (Ball._HEIGHT - 145) * 0.5, 'preloaderBg'); - this.preloadBar = this.add.sprite((Ball._WIDTH - 158) * 0.5, (Ball._HEIGHT - 50) * 0.5, 'preloaderBar'); + this.preloadBg = this.add.sprite( + (Ball._WIDTH - 297) * 0.5, + (Ball._HEIGHT - 145) * 0.5, + "preloaderBg" + ); + this.preloadBar = this.add.sprite( + (Ball._WIDTH - 158) * 0.5, + (Ball._HEIGHT - 50) * 0.5, + "preloaderBar" + ); this.load.setPreloadSprite(this.preloadBar); - this.load.image('ball', 'img/ball.png'); + this.load.image("ball", "img/ball.png"); // … - this.load.spritesheet('button-start', 'img/button-start.png', 146, 51); + this.load.spritesheet("button-start", "img/button-start.png", 146, 51); // … - this.load.audio('audio-bounce', ['audio/bounce.ogg', 'audio/bounce.mp3', 'audio/bounce.m4a']); + this.load.audio("audio-bounce", [ + "audio/bounce.ogg", + "audio/bounce.mp3", + "audio/bounce.m4a", + ]); }, create() { - this.game.state.start('MainMenu'); - } + this.game.state.start("MainMenu"); + }, }; ``` @@ -155,19 +173,28 @@ There are single images, spritesheets and audio files loaded by the framework. I The `MainMenu` state shows the main menu of the game, where you can start playing by clicking the button. ```js -Ball.MainMenu = function(game) {}; +Ball.MainMenu = function (game) {}; Ball.MainMenu.prototype = { create() { - this.add.sprite(0, 0, 'screen-mainmenu'); - this.gameTitle = this.add.sprite(Ball._WIDTH * 0.5, 40, 'title'); - this.gameTitle.anchor.set(0.5,0); - this.startButton = this.add.button(Ball._WIDTH * 0.5, 200, 'button-start', this.startGame, this, 2, 0, 1); - this.startButton.anchor.set(0.5,0); + this.add.sprite(0, 0, "screen-mainmenu"); + this.gameTitle = this.add.sprite(Ball._WIDTH * 0.5, 40, "title"); + this.gameTitle.anchor.set(0.5, 0); + this.startButton = this.add.button( + Ball._WIDTH * 0.5, + 200, + "button-start", + this.startGame, + this, + 2, + 0, + 1 + ); + this.startButton.anchor.set(0.5, 0); this.startButton.input.useHandCursor = true; }, startGame() { - this.game.state.start('Howto'); - } + this.game.state.start("Howto"); + }, }; ``` @@ -189,14 +216,20 @@ When the start button is pressed, instead of jumping directly into the action th ### Howto.js ```js -Ball.Howto = function(game) {}; +Ball.Howto = function (game) {}; Ball.Howto.prototype = { create() { - this.buttonContinue = this.add.button(0, 0, 'screen-howtoplay', this.startGame, this); + this.buttonContinue = this.add.button( + 0, + 0, + "screen-howtoplay", + this.startGame, + this + ); }, startGame() { - this.game.state.start('Game'); - } + this.game.state.start("Game"); + }, }; ``` @@ -207,7 +240,7 @@ The `Howto` state shows the gameplay instructions on the screen before starting The `Game` state from the `Game.js` file is where all the magic happens. All the initialization is in the `create()` function (launched once at the beginning of the game). After that some functionality will require further code to control — we will write our own functions to handle more complicated tasks. In particular, take note of the `update()` function (executed at every frame), which updates things such as the ball position. ```js -Ball.Game = function(game) {}; +Ball.Game = function (game) {}; Ball.Game.prototype = { create() {}, initLevels() {}, @@ -218,7 +251,7 @@ Ball.Game.prototype = { update() {}, wallCollision() {}, handleOrientation(e) {}, - finishLevel() {} + finishLevel() {}, }; ``` @@ -238,7 +271,7 @@ The `create` and `update` functions are framework-specific, while others will be First, let's go to the `create()` function, initialize the ball object itself and assign a few properties to it: ```js -this.ball = this.add.sprite(this.ballStartPos.x, this.ballStartPos.y, 'ball'); +this.ball = this.add.sprite(this.ballStartPos.x, this.ballStartPos.y, "ball"); this.ball.anchor.set(0.5); this.physics.enable(this.ball, Phaser.Physics.ARCADE); this.ball.body.setSize(18, 18); @@ -304,7 +337,7 @@ The more you tilt the device, the more force is applied to the ball, therefore t The main objective in the game is to move the ball from the starting position to the ending position: a hole in the ground. Implementation looks very similar to the part where we created the ball, and it's also added in the `create()` function of our `Game` state: ```js -this.hole = this.add.sprite(Ball._WIDTH * 0.5, 90, 'hole'); +this.hole = this.add.sprite(Ball._WIDTH * 0.5, 90, "hole"); this.physics.enable(this.hole, Phaser.Physics.ARCADE); this.hole.anchor.set(0.5); this.hole.body.setSize(2, 2); @@ -320,13 +353,11 @@ To hold the block information we'll use a level data array: for each block we'll ```js this.levelData = [ + [{ x: 96, y: 224, t: "w" }], [ - { x: 96, y: 224, t: 'w' } - ], - [ - { x: 72, y: 320, t: 'w' }, - { x: 200, y: 320, t: 'h' }, - { x: 72, y: 150, t: 'w' } + { x: 72, y: 320, t: "w" }, + { x: 200, y: 320, t: "h" }, + { x: 72, y: 150, t: "w" }, ], // … ]; @@ -343,7 +374,7 @@ for (let i = 0; i < this.maxLevels; i++) { const item = this.levelData[i][e]; newLevel.create(item.x, item.y, `element-${item.t}`); } - newLevel.setAll('body.immovable', true); + newLevel.setAll("body.immovable", true); newLevel.visible = false; this.levels.push(newLevel); } @@ -370,8 +401,20 @@ Thanks to that the game gives the player a challenge - now they have to roll the At this point we've got the ball that is controlled by the player, the hole to reach and the obstacles blocking the way. There's a problem though — our game doesn't have any collision detection yet, so nothing happens when the ball hits the blocks — it just goes through. Let's fix it! The good news is that the framework will take care of calculating the collision detection, we only have to specify the colliding objects in the `update()` function: ```js -this.physics.arcade.collide(this.ball, this.borderGroup, this.wallCollision, null, this); -this.physics.arcade.collide(this.ball, this.levels[this.level - 1], this.wallCollision, null, this); +this.physics.arcade.collide( + this.ball, + this.borderGroup, + this.wallCollision, + null, + this +); +this.physics.arcade.collide( + this.ball, + this.levels[this.level - 1], + this.wallCollision, + null, + this +); ``` This will tell the framework to execute the `wallCollision` function when the ball hits any of the walls. We can use the `wallCollision` function to add any functionality we want like playing the bounce sound and implementing the **Vibration API**. @@ -381,7 +424,7 @@ This will tell the framework to execute the `wallCollision` function when the ba Among the preloaded assets there was an audio track (in various formats for browser compatibility), which we can use now. It has to be defined in the `create()` function first: ```js -this.bounceSound = this.game.add.audio('audio-bounce'); +this.bounceSound = this.game.add.audio("audio-bounce"); ``` If the status of the audio is `true` (so the sounds in the game are enabled), we can play it in the `wallCollision` function: @@ -422,8 +465,18 @@ this.totalTimer = 0; // time elapsed in the whole game Then, right after that, we can initialize the necessary text objects to display this information to the user: ```js -this.timerText = this.game.add.text(15, 15, `Time: ${this.timer}`, this.fontBig); -this.totalTimeText = this.game.add.text(120, 30, `Total time: ${this.totalTimer}`, this.fontSmall); +this.timerText = this.game.add.text( + 15, + 15, + `Time: ${this.timer}`, + this.fontBig +); +this.totalTimeText = this.game.add.text( + 120, + 30, + `Total time: ${this.totalTimer}`, + this.fontSmall +); ``` We're defining the top and left positions of the text, the content that will be shown and the styling applied to the text. We have this printed out on the screen, but it would be good to update the values every second: diff --git a/files/en-us/games/tutorials/index.md b/files/en-us/games/tutorials/index.md index 0b0047c931ef72d..15d1d6e277e36b9 100644 --- a/files/en-us/games/tutorials/index.md +++ b/files/en-us/games/tutorials/index.md @@ -8,6 +8,7 @@ tags: - Web - Workflows --- + {{GamesSidebar}} This page contains multiple tutorial series that highlight different workflows for effectively creating different types of web games. diff --git a/files/en-us/games/tutorials/touch_event_horizon/index.md b/files/en-us/games/tutorials/touch_event_horizon/index.md index 732452f275c2fb1..068e57c5a6c5081 100644 --- a/files/en-us/games/tutorials/touch_event_horizon/index.md +++ b/files/en-us/games/tutorials/touch_event_horizon/index.md @@ -5,6 +5,7 @@ tags: - NeedsContent - NeedsExample --- + {{GamesSidebar}} This article is for Touch Event Horizon and A Game Related To It From 45bf1330520973102609a5fe458e92ae4b1de22f Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Wed, 24 Aug 2022 19:25:17 -0400 Subject: [PATCH 2/4] fix: use prettier-ignore for explicit semicolon --- files/en-us/games/anatomy/index.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/files/en-us/games/anatomy/index.md b/files/en-us/games/anatomy/index.md index 53f752c4d25e022..e02748468ace107 100644 --- a/files/en-us/games/anatomy/index.md +++ b/files/en-us/games/anatomy/index.md @@ -56,6 +56,7 @@ 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). + ```js /* * Starting with the semicolon is in case whatever line of code above this example @@ -64,7 +65,7 @@ There are two obvious issues with our previous main loop: `main()` pollutes the * marks the beginning of our new line if the previous one was not empty or terminated. */ -(() => { +;(() => { function main() { window.requestAnimationFrame(main); @@ -74,6 +75,7 @@ There are two obvious issues with our previous main loop: `main()` pollutes the main(); // Start the cycle })(); ``` + 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. @@ -81,6 +83,7 @@ When the browser comes across this IIFE, it will define your main loop and immed 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: + ```js /* * Starting with the semicolon is in case whatever line of code above this example @@ -91,7 +94,7 @@ For the second issue, stopping the main loop, you will need to cancel the call t * Let us also assume that MyGame is previously defined. */ -(() => { +;(() => { function main() { MyGame.stopMain = window.requestAnimationFrame(main); @@ -101,6 +104,7 @@ For the second issue, stopping the main loop, you will need to cancel the call t main(); // Start the cycle })(); ``` + 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. @@ -135,6 +139,7 @@ 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. + ```js /* * Starting with the semicolon is in case whatever line of code above this example @@ -145,7 +150,7 @@ Back to the topic of the main loop. You will often want to know when your main f * Let us also assume that MyGame is previously defined. */ -(() => { +;(() => { function main(tFrame) { MyGame.stopMain = window.requestAnimationFrame(main); @@ -156,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 })(); ``` + 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. @@ -169,6 +175,7 @@ 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. + ```js /* * Starting with the semicolon is in case whatever line of code above this example @@ -179,7 +186,7 @@ If your game can hit the maximum refresh rate of any hardware you support then y * Let us also assume that MyGame is previously defined. */ -(() => { +;(() => { function main(tFrame) { MyGame.stopMain = window.requestAnimationFrame(main); @@ -190,6 +197,7 @@ If your game can hit the maximum refresh rate of any hardware you support then y main(); // Start the cycle })(); ``` + 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: @@ -230,6 +238,7 @@ A separate update and draw method could look like the following example. For the > **Warning:** This example, specifically, is in need of technical review. + ```js /* * Starting with the semicolon is in case whatever line of code above this example @@ -259,7 +268,7 @@ A separate update and draw method could look like the following example. For the * It is just a generic example function that you might have added. */ -(() => { +;(() => { function main(tFrame) { MyGame.stopMain = window.requestAnimationFrame(main); const nextTick = MyGame.lastTick + MyGame.tickLength; @@ -294,6 +303,7 @@ A separate update and draw method could look like the following example. For the main(performance.now()); // Start the cycle })(); ``` + 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). From 3e59fef84be33a61387d76121f88766a0384e2a4 Mon Sep 17 00:00:00 2001 From: Jean-Yves Perrier Date: Thu, 25 Aug 2022 09:54:44 +0200 Subject: [PATCH 3/4] Update files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md Co-authored-by: rubiesonthesky <2591240+rubiesonthesky@users.noreply.github.com> --- .../build_the_brick_field/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md index d82457a0ac40feb..38c9500e53e1a9f 100644 --- a/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md +++ b/files/en-us/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md @@ -107,7 +107,7 @@ drawBricks(); ## Compare your code -At this point, the game has got a little more interesting again : +At this point, the game has got a little more interesting again: {{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/Lu3vtejz/","","395")}} From c74403303b74df69990fe8c7ed857fb605d16a21 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Thu, 25 Aug 2022 11:13:09 -0400 Subject: [PATCH 4/4] chore: use Prettier bracketSameLine --- .prettierrc.json | 3 +++ .../index.md | 18 ++++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) create mode 100644 .prettierrc.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000000000..9c1044f6f67e6ff --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "bracketSameLine": true +} diff --git a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md index d44f03a87e43832..6b05b2d3492afe1 100644 --- a/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md +++ b/files/en-us/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_a-frame/index.md @@ -110,8 +110,7 @@ A camera entity can be created by adding an [``](https://aframe.io/doc cursor-visible="true" cursor-scale="2" cursor-color="#0095DD" - cursor-opacity="0.5" -> + cursor-opacity="0.5"> ``` @@ -141,8 +140,7 @@ We have a cube on the scene already; now let's try adding more shapes. We are no radiusTubular: 0.1; segmentsTubular: 12;" rotation="10 0 0" - position="-3 1 0" -> + position="-3 1 0"> ``` @@ -164,8 +162,7 @@ The torus is now visible on the scene, but its color doesn't look very good — roughness: 0.1; metalness: 0.5;" rotation="10 0 0" - position="-3 1 0" -> + position="-3 1 0"> ``` @@ -208,8 +205,7 @@ There's a special [``](https://aframe.io/docs/core/animation.html) direction="alternate" dur="4000" repeat="indefinite" - easing="ease" - > + easing="ease"> ``` @@ -232,16 +228,14 @@ We can also add animation to entities with custom geometry like the torus, in mu roughness: 0.1; metalness: 0.5;" rotation="10 0 0" - position="-3 1 0" -> + position="-3 1 0"> + easing="linear"> ```