Comment créer un jeu simple dans le navigateur avec Phaser 3 et TypeScript

Photo par Phil Botha sur Unsplash

Je suis un défenseur des droits des développeurs et un développeur backend. Mon expertise en développement frontend est relativement faible. Il y a quelque temps, je voulais m'amuser et créer un jeu dans un navigateur. J'ai choisi Phaser 3 comme framework (il a l'air assez populaire de nos jours) et TypeScript comme langage (car je préfère le typage statique au dynamique). Il s'est avéré que vous deviez faire des choses ennuyeuses pour que tout fonctionne, alors j'ai écrit ce tutoriel pour aider les autres personnes comme moi à démarrer plus rapidement.

Préparer l'environnement

IDE

Choisissez votre environnement de développement. Vous pouvez toujours utiliser le vieux bloc-notes si vous le souhaitez, mais je suggérerais d'utiliser quelque chose de plus utile. Quant à moi, je préfère développer des projets pour animaux de compagnie à Emacs, donc j’ai installé Tide et suivi les instructions pour le configurer.

Nœud

Si nous développions sur JavaScript, nous serions parfaitement en mesure de commencer à coder sans toutes ces étapes de préparation. Cependant, comme nous voulons utiliser TypeScript, nous devons configurer l'infrastructure pour rendre le développement futur aussi rapide que possible. Nous devons donc installer node et npm.

Au moment d’écrire ce tutoriel, j’utilise les nœuds 10.13.0 et 6.4.1. Veuillez noter que les versions du monde frontal se mettent à jour extrêmement rapidement, vous prenez donc simplement les dernières versions stables. Je recommande fortement d'utiliser nvm au lieu d'installer node et npm manuellement; cela vous fera économiser beaucoup de temps et de nerfs.

Mise en place du projet

Structure de projet

Nous allons utiliser npm pour créer le projet. Pour le démarrer, accédez à un dossier vide et exécutez npm init. npm vous posera plusieurs questions sur les propriétés de votre projet, puis créera un fichier package.json. Cela ressemblera à ceci:

{
  "name": "Starfall",
  "version": "0.1.0",
  "description": "Jeu Starfall (Phaser 3 + TypeScript)",
  "main": "index.js",
  "scripts": {
    "test": "echo \" Erreur: aucun test spécifié \ "&& exit 1"
  },
  "auteur": "Mariya Davydova",
  "licence": "MIT"
}

Paquets

Installez les paquets dont nous avons besoin avec la commande suivante:

npm install -D typescript webpack webpack-cli serveur ts-loader phaser live

L'option -D (a.k.a. --save-dev) permet à npm d'ajouter ces packages à la liste des dépendances de package.json automatiquement:

"devDependencies": {
   "live-server": "^ 1.2.1",
   "phaser": "^ 3.15.1",
   "ts-loader": "^ 5.3.0",
   "typescript": "^ 3.1.6",
   "webpack": "^ 4.26.0",
   "webpack-cli": "^ 3.1.2"
 }

Webpack

Webpack exécutera le compilateur TypeScript et rassemblera le lot de fichiers JS ainsi que les bibliothèques dans un seul JS minifié afin que nous puissions l'inclure dans notre page.

Ajoutez webpack.config.js près de votre projet.json:

const path = require ('path');
module.exports = {
  entrée: './src/app.ts',
  module: {
    règles: [
      {
        test: /\.tsx?$/,
        utiliser: 'ts-loader',
        exclure: / node_modules /
      }
    ]
  },
  résoudre: {
    extensions: ['.ts', '.tsx', '.js']
  },
  sortie: {
    nom de fichier: 'app.js',
    path: path.resolve (__ dirname, 'dist')
  },
  mode: 'développement'
};

Nous voyons ici que webpack doit récupérer les sources à partir de src / app.ts (que nous ajouterons très bientôt) et tout collecter dans le fichier dist / app.js.

Manuscrit

Nous avons également besoin d'un petit fichier de configuration pour le compilateur TypeScript (tsconfig.json), dans lequel nous expliquons quelle version de JS nous voulons compiler les sources et où trouver ces sources:

{
  "compilerOptions": {
    "cible": "es5"
  },
  "comprendre": [
    "src / *"
  ]
}

Définitions TypeScript

TypeScript est un langage statiquement typé. Par conséquent, il nécessite des définitions de type pour la compilation. Au moment de la rédaction de ce tutoriel, les définitions de Phaser 3 n'étant pas encore disponibles dans le package npm, vous devrez peut-être les télécharger à partir du référentiel officiel et placer le fichier dans le sous-répertoire src de votre projet.

Les scripts

Nous avons presque terminé le projet mis en place. À ce moment, vous devriez avoir créé package.json, webpack.config.js et tsconfig.json, et ajouté src / phaser.d.ts. La dernière chose à faire avant de commencer à écrire du code est d'expliquer ce que npm a à voir avec le projet. Nous mettons à jour la section des scripts du package.json comme suit:

"scripts": {
  "build": "webpack",
  "start": "webpack --watch & live-server --port = 8085"
}

Lorsque vous exécutez npm build, le fichier app.js sera construit conformément à la configuration de Webpack. Et lorsque vous exécutez npm start, vous n’aurez plus à vous soucier du processus de construction: dès que vous enregistrez une source, Webpack reconstruira l’application et le serveur live la rechargera dans votre navigateur par défaut. L'application sera hébergée à l'adresse http://127.0.0.1:8085/.

Commencer

Maintenant que nous avons mis en place l'infrastructure (la partie que je déteste personnellement lorsque je commence un projet), nous pouvons enfin commencer à coder. Dans cette étape, nous allons faire une chose simple: dessinez un rectangle bleu foncé dans la fenêtre de votre navigateur. Utiliser un framework de développement de gros jeux pour cela est un peu… hmmm… excessif. Néanmoins, nous en aurons besoin lors des prochaines étapes.

Permettez-moi de vous expliquer brièvement les principaux concepts de Phaser 3. Le jeu est une instance de la classe Phaser.Game (ou de son descendant). Chaque jeu contient une ou plusieurs instances de descendants de Phaser.Scene. Chaque scène contient plusieurs objets, statiques ou dynamiques, et représente une partie logique du jeu. Par exemple, notre jeu trivial aura trois scènes: l'écran de bienvenue, le jeu lui-même et l'écran de score.

Commençons par coder.

Tout d’abord, créez un conteneur HTML minimaliste pour le jeu. Créez un fichier index.html contenant le code suivant:



  
     Météores </ title>
    <script src = "dist / app.js"> </ script>
  </ head>
  <body>
    <div id = "game"> </ div>
  </ body>
</ html></pre><p>Il n'y a que deux parties essentielles ici: la première est une entrée de script qui indique que nous allons utiliser notre fichier construit ici, et la seconde est une entrée div qui sera le conteneur de jeu.</p><p>Maintenant, créez un fichier src / app.ts avec le code suivant:</p><pre>importer "phaser";</pre><pre>const config: GameConfig = {
  titre: "Météores",
  largeur: 800
  hauteur: 600,
  parent: "jeu"
  backgroundColor: "# 18216D"
};</pre><pre>La classe d'exportation StarfallGame étend Phaser.Game {
  constructeur (config: GameConfig) {
    super (config);
  }
}</pre><pre>window.onload = () => {
  var game = new StarfallGame (config);
};</pre><p>Ce code est explicite. GameConfig a beaucoup de propriétés différentes, vous pouvez les vérifier ici.</p><p>Et maintenant, vous pouvez enfin lancer npm start. Si tout a été fait correctement lors de cette étape et des étapes précédentes, vous devriez voir quelque chose d'aussi simple que cela dans votre navigateur:</p><img alt="Oui, ceci est un écran bleu." src="https://imgstore.nyc3.cdn.digitaloceanspaces.com/ceadesc/1569967675050.png" /><h3>Faire tomber les étoiles</h3><p>Nous avons créé une application élémentaire. Il est maintenant temps d’ajouter une scène où quelque chose va se passer. Notre jeu sera simple: les étoiles tomberont au sol et le but sera d’en attraper le plus possible.</p><p>Pour atteindre cet objectif, créez un nouveau fichier, gameScene.ts, et ajoutez le code suivant:</p><pre>importer "phaser";</pre><pre>La classe d'exportation GameScene étend Phaser.Scene {</pre><pre>constructeur () {
    super({
      clé: "GameScene"
    });
  }</pre><pre>init (params): void {
    // FAIRE
  }</pre><pre>précharge (): void {
    // FAIRE
  }
  
  create (): void {
    // FAIRE
  }</pre><pre>mise à jour (heure): void {
    // FAIRE
  }
};</pre><p>Constructeur contient ici une clé sous laquelle d’autres scènes peuvent appeler cette scène.</p><p>Vous voyez ici des stubs pour quatre méthodes. Permettez-moi d'expliquer brièvement la différence entre alors:</p><ul><li>init ([params]) est appelé au démarrage de la scène; cette fonction peut accepter des paramètres, qui sont transmis depuis d'autres scènes ou jeux en appelant scene.start (key, [params])</li><li>preload () est appelé avant la création des objets de la scène et contient des éléments en cours de chargement; ces actifs sont mis en cache. Ainsi, au redémarrage de la scène, ils ne sont pas rechargés.</li><li>create () est appelé lorsque les éléments sont chargés et contient généralement la création des objets principaux du jeu (arrière-plan, joueur, obstacles, ennemis, etc.)</li><li>update ([heure]) est appelé à chaque tick et contient la partie dynamique de la scène - tout ce qui bouge, clignote, etc.</li></ul><p>Pour être sûr de ne pas l’oublier plus tard, ajoutons rapidement les lignes suivantes dans le jeu.:</p><pre>importer "phaser";
importer {GameScene} depuis "./gameScene";</pre><pre>const config: GameConfig = {
  titre: "Météores",
  largeur: 800
  hauteur: 600,
  parent: "jeu",
  scène: [GameScene],
  la physique: {
    défaut: "arcade",
    arcade: {
      débogage: faux
    }
  },
  backgroundColor: "# 000033"
};
...</pre><p>Notre jeu connaît maintenant la scène du jeu. Si la configuration du jeu contient une liste de scènes, la première est lancée au début du jeu et toutes les autres sont créées mais ne sont pas démarrées tant qu'elles n'ont pas été explicitement appelées.</p><p>Nous avons également ajouté la physique d'arcade ici. Il est nécessaire de faire tomber nos étoiles.</p><p>Nous pouvons maintenant donner corps aux os de notre scène de jeu.</p><p>Premièrement, nous déclarons certaines propriétés et objets dont nous aurons besoin:</p><pre>La classe d'exportation GameScene étend Phaser.Scene {
  delta: nombre;
  lastStarTime: nombre;
  starsCaught: nombre;
  étoilesFallen: nombre;
  sand: Phaser.Physics.Arcade.StaticGroup;
  info: Phaser.GameObjects.Text;
...</pre><p>Ensuite, on initialise les nombres:</p><pre>init (/ * params: any * /): void {
    this.delta = 1000;
    this.lastStarTime = 0;
    this.starsCaught = 0;
    this.starsFallen = 0;
  }</pre><p>Maintenant, nous chargeons quelques images:</p><pre>précharge (): void {
    this.load.setBaseURL (
      "https://raw.githubusercontent.com/mariyadavydova/" +
      "starfall-phaser3-typescript / master /");
    this.load.image ("étoile", "assets / étoile.png");
    this.load.image ("sand", "assets / sand.jpg");
  }</pre><p>Après cela, nous pouvons préparer nos composants statiques. Nous allons créer le sol, où les étoiles vont tomber, et le texte nous informant sur le score actuel:</p><pre>create (): void {
    this.sand = this.physics.add.staticGroup ({
      clé: 'sable',
      quantité de cadre: 20
    });
    Phaser.Actions.PlaceOnLine (this.sand.getChildren (),
      nouveau Phaser.Geom.Line (20, 580, 820, 580));
    this.sand.refresh ();</pre><pre>this.info = this.add.text (10, 10, '',
      {font: '24px Arial Bold', remplissez: '#FBFBAC'});
  }</pre><p>Un groupe dans Phaser 3 est un moyen de créer un groupe d’objets que vous souhaitez contrôler ensemble. Il existe deux types d’objets: statique et dynamique. Comme vous pouvez le deviner, les objets statiques ne bougent pas (sol, murs, obstacles divers), tandis que les objets dynamiques font le travail (Mario, navires, missiles).</p><p>Nous créons un groupe statique de pièces au sol. Ces pièces sont placées le long de la ligne. Veuillez noter que la ligne est divisée en 20 sections égales (et non 19 comme vous l’auriez peut-être prévu) et que les tuiles au sol sont placées sur chaque section à l’extrémité gauche, avec le centre de la tuile situé à cet endroit (j’espère que cela explique Nombres). Nous devons également appeler refresh () pour mettre à jour la boîte englobante du groupe (sinon, les collisions seront vérifiées par rapport à l'emplacement par défaut, qui est le coin supérieur gauche de la scène).</p><p>Si vous extrayez votre application dans le navigateur maintenant, vous devriez voir quelque chose comme ceci:</p><img alt="Évolution de l'écran bleu" src="https://imgstore.nyc3.cdn.digitaloceanspaces.com/ceadesc/1569967676394.png" /><p>Nous avons enfin atteint la partie la plus dynamique de cette scène - la fonction update (), où les étoiles tombent. Cette fonction est appelée quelque part environ une fois en 60 ms. Nous voulons émettre une nouvelle étoile filante à chaque seconde. Nous n’utiliserons pas de groupe dynamique à cet effet, car le cycle de vie de chaque étoile sera court: il sera détruit soit par clic de l’utilisateur, soit par collision avec le sol. Par conséquent, dans la fonction emitStar (), nous créons une nouvelle étoile et ajoutons le traitement de deux événements: onClick () et onCollision ().</p><pre>mise à jour (heure: nombre): void {
    var diff: nombre = heure - this.lastStarTime;
    if (diff> this.delta) {
      this.lastStarTime = heure;
      si (this.delta> 500) {
        this.delta - = 20;
      }
      this.emitStar ();
    }
    this.info.text =
      this.starsCaught + "attrapé -" +
      this.starsFallen + "tombé (max 3)";
  }</pre><pre>onClick privé (étoile: Phaser.Physics.Arcade.Image): () => void {
    fonction de retour () {
      star.setTint (0x00ff00);
      star.setVelocity (0, 0);
      this.starsCaught + = 1;
      this.time.delayedCall (100, fonction (étoile) {
        star.destroy ();
      }, [étoile], cela);
    }
  }</pre><pre>onFall privé (étoile: Phaser.Physics.Arcade.Image): () => void {
    fonction de retour () {
      star.setTint (0xff0000);
      this.starsFallen + = 1;
      this.time.delayedCall (100, fonction (étoile) {
        star.destroy ();
      }, [étoile], cela);
    }
  }</pre><pre>emitStar privé (): void {
    var star: Phaser.Physics.Arcade.Image;
    var x = Phaser.Math.Between (25, 775);
    var y = 26;
    étoile = this.physics.add.image (x, y, "étoile");</pre><pre>star.setDisplaySize (50, 50);
    star.setVelocity (0, 200);
    star.setInteractive ();</pre><pre>star.on ('pointerdown', this.onClick (star), this);
    this.physics.add.collider (star, this.sand,
      this.onFall (star), null, cela);
  }</pre><p>Enfin, nous avons un jeu! Il n’a pas encore de condition de victoire. Nous allons l’ajouter dans la dernière partie de notre tutoriel.</p><img alt="Je suis mauvais pour attraper des étoiles…" src="https://imgstore.nyc3.cdn.digitaloceanspaces.com/ceadesc/1569967677698.png" /><h3>Envelopper le tout</h3><p>Habituellement, un jeu consiste en plusieurs scènes. Même si le gameplay est simple, vous avez besoin d’une scène d’ouverture (contenant au minimum le bouton ‘Play!’) Et d’une scène de fermeture (affichant le résultat de votre session de jeu, comme le score ou le niveau maximum atteint). Ajoutons ces scènes à notre application.</p><p>Dans notre cas, ils seront assez similaires, car je ne veux pas prêter trop d’attention à la conception graphique du jeu. Après tout, c’est un tutoriel de programmation.</p><p>La scène de bienvenue aura le code suivant dans welcomeScene.ts. Notez que lorsqu'un utilisateur clique quelque part sur cette scène, une scène de jeu apparaîtra.</p><pre>importer "phaser";</pre><pre>La classe d’exportation WelcomeScene étend Phaser.Scene {
  titre: Phaser.GameObjects.Text;
  Indice: Phaser.GameObjects.Text;</pre><pre>constructeur () {
    super({
      clé: "WelcomeScene"
    });
  }</pre><pre>create (): void {
    var titleText: string = "Starfall";
    this.title = this.add.text (150, 200, titleText,
      {font: '128px Arial Bold', remplissez: '#FBFBAC'});</pre><pre>var hintText: string = "Cliquez pour commencer";
    this.hint = this.add.text (300, 350, hintText,
      {font: '24px Arial Bold', remplissez: '#FBFBAC'});</pre><pre>this.input.on ('pointerdown', fonction (/ * pointeur * /) {
      this.scene.start ("GameScene");
    }, cette);
  }
};</pre><p>La scène de partition aura presque la même apparence, ce qui mènera à la scène de bienvenue par clic (scoreScene.ts).</p><pre>importer "phaser";</pre><pre>La classe d'exportation ScoreScene étend Phaser.Scene {
  score: nombre;
  résultat: Phaser.GameObjects.Text;
  Indice: Phaser.GameObjects.Text;</pre><pre>constructeur () {
    super({
      clé: "ScoreScene"
    });
  }</pre><pre>init (params: any): void {
    this.score = params.starsCaught;
  }</pre><pre>create (): void {
    var resultText: string = 'Votre score est' + this.score + '!';
    this.result = this.add.text (200, 250, resultText,
      {font: '48px Arial Bold', remplissez: '#FBFBAC'});</pre><pre>var hintText: string = "Cliquez pour redémarrer";
    this.hint = this.add.text (300, 350, hintText,
      {font: '24px Arial Bold', remplissez: '#FBFBAC'});</pre><pre>this.input.on ('pointerdown', fonction (/ * pointeur * /) {
      this.scene.start ("WelcomeScene");
    }, cette);
  }
};</pre><p>Nous devons mettre à jour notre fichier d’application principal maintenant: ajoutez ces scènes et faites de WelcomeScene le premier de la liste:</p><pre>importer "phaser";
importer {WelcomeScene} de "./welcomeScene";
importer {GameScene} depuis "./gameScene";
importer {ScoreScene} depuis "./scoreScene";</pre><pre>const config: GameConfig = {
  ...
  scène: [WelcomeScene, GameScene, ScoreScene],
  ...</pre><p>Avez-vous remarqué ce qui manque? Oui, nous n’appelons pas encore ScoreScene de n’importe où! Appelons-le quand le joueur a manqué la troisième étoile:</p><pre>onFall privé (étoile: Phaser.Physics.Arcade.Image): () => void {
    fonction de retour () {
      star.setTint (0xff0000);
      this.starsFallen + = 1;
      this.time.delayedCall (100, fonction (étoile) {
        star.destroy ();
        if (this.starsFallen> 2) {
          this.scene.start ("ScoreScene",
            {starsCaught: this.starsCaught});
        }
      }, [étoile], cela);
    }
  }</pre><p>Enfin, notre jeu Starfall ressemble à un vrai jeu - il commence, se termine et a même un objectif à archiver (combien d'étoiles pouvez-vous attraper?).</p><p>J'espère que ce tutoriel est aussi utile pour vous que pour moi quand je l'ai écrit :) Tous les commentaires sont très appréciés!</p><p>Le code source de ce tutoriel peut être trouvé ici.</p></div><div class="neighbor-articles"><h4 class="ui header">Voir également</h4><a href="/question/how-to-connect-samsung-note-5-to-computer/" title="comment connecter le samsung note 5 à un ordinateur">comment connecter le samsung note 5 à un ordinateur</a><a href="/question/how-to-turn-on-epson-projector-without-remote/" title="comment allumer le projecteur epson sans télécommande">comment allumer le projecteur epson sans télécommande</a><a href="/question/how-to-determine-if-a-matrix-is-singular/" title="comment déterminer si une matrice est singulière">comment déterminer si une matrice est singulière</a><a href="/question/how-to-paralyze-yourself/" title="comment se paralyser">comment se paralyser</a><a href="/question/how-to-say-wet-paint-in-spanish/" title="comment dire peinture humide en espagnol">comment dire peinture humide en espagnol</a><a href="/question/how-to-install-avada/" title="comment installer avada">comment installer avada</a><a href="/question/how-to-test-for-endogeneity/" title="comment tester l'endogénéité">comment tester l'endogénéité</a><a href="/question/how-to-open-a-stapler-all-the-way/" title="comment ouvrir une agrafeuse complètement">comment ouvrir une agrafeuse complètement</a></div></div><div class="article-sidebar"><div class="neighbor-articles"><h4 class="ui header">Voir également</h4><a href="/article/the-burden-of-making-decisions-and-how-to-break-the-toxic-cycle-of-procrastination-51b2e8/" title="Le fardeau de prendre des décisions et comment briser le cycle toxique de la procrastination.">Le fardeau de prendre des décisions et comment briser le cycle toxique de la procrastination.</a><a href="/article/how-to-make-work-better-bcc75a/" title="Comment améliorer le travail">Comment améliorer le travail</a><a href="/article/a-practical-guide-on-how-to-stop-people-pleasing-and-start-being-yourself-50e709/" title="Un guide pratique sur la façon d'arrêter de plaire et de commencer à être soi-même">Un guide pratique sur la façon d'arrêter de plaire et de commencer à être soi-même</a><a href="/article/how-to-update-the-apollo-client-s-cache-after-a-mutation-929230/" title="Comment mettre à jour le cache du client Apollo après une mutation">Comment mettre à jour le cache du client Apollo après une mutation</a><a href="/article/how-to-put-the-reader-in-the-story-with-description-aabaab/" title="Comment mettre le lecteur dans l'histoire avec une description">Comment mettre le lecteur dans l'histoire avec une description</a><a href="/article/how-to-start-a-successful-side-hustle-and-make-1000-mo-or-more-98634d/" title="Comment faire pour démarrer un side hustle et gagner 1000 $ / mois ou plus">Comment faire pour démarrer un side hustle et gagner 1000 $ / mois ou plus</a><a href="/article/how-to-optimize-your-writing-toolbox-and-determine-what-type-of-writer-you-want-to-be-d2d588/" title="Comment optimiser votre boîte à outils d'écriture et déterminer quel type d'écrivain vous souhaitez être">Comment optimiser votre boîte à outils d'écriture et déterminer quel type d'écrivain vous souhaitez être</a><a href="/article/how-to-handle-adult-temper-tantrums-982625/" title="Comment gérer les crises de colère des adultes">Comment gérer les crises de colère des adultes</a></div></div></div></main><div class="push"></div></div><footer><div class="flags-footer"><a href="https://uz.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="uz flag"></i></a><a href="https://bg.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="bg flag"></i></a><a href="https://et.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ee flag"></i></a><a href="https://lt.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="lt flag"></i></a><a href="https://lv.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="lv flag"></i></a><a href="https://sr.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="rs flag"></i></a><a href="https://sl.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="si flag"></i></a><a href="https://sk.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="sk flag"></i></a><a href="https://uk.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ua flag"></i></a><a href="https://sq.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="al flag"></i></a><a href="https://hy.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="am flag"></i></a><a href="https://is.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="is flag"></i></a><a href="https://az.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="az flag"></i></a><a href="https://kk.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="kz flag"></i></a><a href="https://fa.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ir flag"></i></a><a href="https://tg.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="tj flag"></i></a><a href="https://ga.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ie flag"></i></a><a href="https://be.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="by flag"></i></a><a href="https://ka.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ge flag"></i></a><a href="https://ky.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="kg flag"></i></a><a href="https://lb.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="lu flag"></i></a><a href="https://lo.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="la flag"></i></a><a href="https://ar.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="sa flag"></i></a><a href="https://bn.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="in flag"></i></a><a href="https://ca.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="es flag"></i></a><a href="https://zh.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="cn flag"></i></a><a href="https://hr.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="hr flag"></i></a><a href="https://cs.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="cz flag"></i></a><a href="https://da.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="dk flag"></i></a><a href="https://nl.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="nl flag"></i></a><a href="https://tl.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ph flag"></i></a><a href="https://fi.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="fi flag"></i></a><a href="https://de.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="de flag"></i></a><a href="https://el.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="gr flag"></i></a><a href="https://iw.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="il flag"></i></a><a href="https://hi.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="in flag"></i></a><a href="https://hu.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="hu flag"></i></a><a href="https://id.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="id flag"></i></a><a href="https://it.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="it flag"></i></a><a href="https://ja.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="jp flag"></i></a><a href="https://ko.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="kr flag"></i></a><a href="https://ms.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="my flag"></i></a><a href="https://mr.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="io flag"></i></a><a href="https://no.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="no flag"></i></a><a href="https://pl.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="pl flag"></i></a><a href="https://pt.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="pt flag"></i></a><a href="https://ro.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ro flag"></i></a><a href="https://ru.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ru flag"></i></a><a href="https://internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="es flag"></i></a><a href="https://sv.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="ch flag"></i></a><a href="https://ta.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="sg flag"></i></a><a href="https://te.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="in flag"></i></a><a href="https://th.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="th flag"></i></a><a href="https://tr.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="tr flag"></i></a><a href="https://ur.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="pk flag"></i></a><a href="https://vi.internautasporlapaz.org/article/how-to-build-a-simple-game-in-the-browser-with-phaser-3-and-typescript-dede14/"><i class="vn flag"></i></a></div>internautasporlapaz.org<!-- --> © <!-- -->2021<!-- --> </footer></div></div></div></body></html>