{"id":298901,"date":"2020-02-19T03:00:11","date_gmt":"2020-02-19T03:00:11","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=298901"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=298901","title":{"rendered":"Golang + Phaser3 = MMORPG \u2014 \u041a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0421\u0435\u0440\u0432\u0435\u0440"},"content":{"rendered":"\n<div class=\"post__text post__text-html\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/488794\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ra\/gk\/at\/ragkatgmqj9evur6anqx3rlos3e.gif\" alt=\"image\"><\/p>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0441 \u0432\u0430\u043c\u0438 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0443, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u0443, \u043d\u0430 \u0447\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0448\u0430 \u0432\u0441\u0435\u043b\u0435\u043d\u043d\u0430\u044f, \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u044d\u0442\u043e \u0441\u043a\u0443\u0447\u043d\u043e \u0438 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043d\u0430\u0448\u0438\u0445 \u0442\u0430\u0439\u043b\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Phaser.js<\/p>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u043b \u0442\u0430\u043a:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/mb\/5r\/nh\/mb5rnhfwbge-ytwhwqk_hu9psrc.png\" alt=\"image\"><\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043d\u0430\u0434\u0435\u044e\u0441\u044c \u0443 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d Node.js \u0438 npm, \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0441\u0440\u043e\u0447\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435. \u0418 \u0442\u0430\u043a \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043c:  <\/p>\n<pre><code class=\"bash\">$ npm install phaser@3.22.0<\/code><\/pre>\n<p>  \u041f\u0440\u0438 \u0443\u0434\u0430\u0447\u043d\u043e\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:  <\/p>\n<pre><code class=\"bash\">+ phaser@3.22.0 added 15 packages from 48 contributors and audited 20 packages in 4.38s <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/kv\/iq\/rd\/kviqrdtp_esg27iy8xdwi1o5mmu.png\" alt=\"image\"><br \/>  \u0422\u0430\u043a \u043e\u0442\u043b\u0438\u0447\u043d\u043e, \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043c\u043e\u0434\u0443\u043b\u0438, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hc\/jg\/bm\/hcjgbmqtqyh5s-yaagdgps8edxq.png\" alt=\"image\"><br \/>  \u0412 Content \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0438\u0433\u0440\u044b, \u0442.\u0435. \u043d\u0430\u0448\u0438 \u0441\u043f\u0440\u0430\u0439\u0442\u044b. \u0422\u0430\u043a \u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 game.js \u0438 MainScene.js, \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435(\u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u0444\u0430\u0439\u043b main.go) \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c index.html<br \/>  game.js \u2014 \u0445\u0440\u0430\u043d\u0438\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u0438\u0433\u0440\u044b<br \/>  MainScene.js \u2014 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b \u0438\u0433\u0440\u044b<br \/>  index.html \u2014 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440 \u0441\u0446\u0435\u043d\u044b<br \/>  \u0421\u0440\u0430\u0437\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0432 index.html \u043d\u0430\u0448\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043c\u044b \u043a \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u043c  <\/p>\n<pre><code class=\"xml\">    &lt;script src=&quot;node_modules\/phaser\/dist\/phaser.js&quot; type=&quot;module&quot;&gt;&lt;\/script&gt;     &lt;script src=&quot;Client\/game.js&quot; type=&quot;module&quot;&gt;&lt;\/script&gt;<\/code><\/pre>\n<p>  \u0412 MainScene.js \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0430\u0448\u0435\u0439 \u0431\u0443\u0434\u0443\u0449\u0435\u0439 \u0441\u0446\u0435\u043d\u044b:  <\/p>\n<pre><code class=\"javascript\">export {MainScene} class MainScene extends Phaser.Scene{ constructor() {     super({key: 'MainScene'}) } preload() {  } create() {  } update() {  } }<\/code><\/pre>\n<p>  \u0412 game.js \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0442\u0438\u043f\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e \u0441\u0432\u043e\u0435\u043c\u0443 \u0432\u043a\u0443\u0441\u0443, \u0432\u043e\u0442 \u043c\u043e\u0438:  <\/p>\n<pre><code class=\"javascript\">import {MainScene} from &quot;.\/MainScene.js&quot;; let config = {     type: Phaser.AUTO,     width: 800,     height: 600,     disableContextMenu: true,     background: 'black',     physics: {         default: 'arcade',         arcadePhysics: {             overlapBias: 1         }     },     scene:[MainScene],     pixelArt: true,     roundPixels: true,     antialias: true  } let game = new Phaser.Game(config);<\/code><\/pre>\n<p>  <a name=\"habracut\"><\/a><br \/>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d HTTP \u0441\u0435\u0440\u0432\u0435\u0440, \u043d\u0430 \u0433\u043e \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a. \u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 main.go \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440:  <\/p>\n<pre><code class=\"go\">package main  import ( \t&quot;fmt&quot; \t&quot;html\/template&quot; \t&quot;net\/http&quot; )  func main() { \t\/\/ \u0420\u043e\u0443\u0442\u0435\u0440 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \thttp.HandleFunc(&quot;\/&quot;, indexHandler) \t\/\/ \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c (\u0441\u043a\u0440\u0438\u043f\u0442\u044b, \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0438 \u0442\u0434.) \thttp.Handle(&quot;\/node_modules\/phaser\/dist\/&quot;, http.StripPrefix(&quot;\/node_modules\/phaser\/dist\/&quot;, http.FileServer(http.Dir(&quot;.\/node_modules\/phaser\/dist\/&quot;)))) \thttp.Handle(&quot;\/Client\/&quot;, http.StripPrefix(&quot;\/Client\/&quot;, http.FileServer(http.Dir(&quot;.\/Client\/&quot;)))) \thttp.Handle(&quot;\/Client\/Content\/&quot;, http.StripPrefix(&quot;\/Client\/Content\/&quot;, http.FileServer(http.Dir(&quot;.\/Client\/Content\/&quot;)))) \t\/\/ \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043b\u044e\u0431\u043e\u0439 \u043f\u043e\u0440\u0442, \u044f \u0432\u044b\u0431\u0440\u0430\u043b 8080 \terr := http.ListenAndServe(&quot;:8080&quot;, nil) \tif err != nil { \t\tfmt.Println(err.Error()) \t} } \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043b\u044f index.html, \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u0434\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e func indexHandler(w http.ResponseWriter, r *http.Request) { \tfmt.Println(&quot;indexAction&quot;) \tt, _ := template.ParseFiles(&quot;index.html&quot;) \terr := t.Execute(w, &quot;index&quot;) \tif err != nil { \t\tfmt.Println(err.Error()) \t} }<\/code><\/pre>\n<p>  \u041d\u0443 \u0432\u043e\u0442, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442! \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0443\u0436\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c! \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u043d\u0441\u043e\u043b\u044c:  <\/p>\n<pre><code class=\"bash\">$ go run main.go<\/code><\/pre>\n<p>  \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e <\/p>\n<blockquote><p>localhost:8080<\/p><\/blockquote>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/k5\/85\/pw\/k585pwr9ihknt_hx2glcnyzgrua.png\" alt=\"image\"><\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438 \u0447\u0435\u0440\u043d\u044b\u0439 \u044d\u043a\u0440\u0430\u043d, \u0437\u043d\u0430\u0447\u0438\u0442 \u0432\u044b \u0432\u0441\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e.<br \/>  \u0418 \u0442\u0430\u043a, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u0430\u0448 \u0447\u0430\u043d\u043a \u0432 json \u0444\u043e\u0440\u043c\u0430\u0442\u0435. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0438 \u043d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0435 GameController, \u0437\u0434\u0435\u0441\u044c \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u0432\u0441\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0435 \u0441 \u0438\u0433\u0440\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b Map_Controller.go <br \/>  \u0422\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u043d\u044b\u0439 <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Chunk.go<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"go\">package Chunk  import ( \t&quot;exampleMMO\/PerlinNoise&quot; \t&quot;fmt&quot; )   var TILE_SIZE = 16 var CHUNK_SIZE = 16 * 16 var PERLIN_SEED float32 = 160  type Chunk struct { \tChunkID [2]int `json:&quot;chunkID&quot;` \tMap     map[Coordinate]Tile `json:&quot;map&quot;` }  \/* \u0422\u0430\u0439\u0442\u043b \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043c\u0438\u0440\u0430 *\/ type Tile struct { \tKey string `json:&quot;key&quot;` \tX   int    `json:&quot;x&quot;` \tY   int    `json:&quot;y&quot;` }  \/* \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 *\/ type Coordinate struct { \tX int `json:&quot;x&quot;` \tY int `json:&quot;y&quot;` }    \/* \u0421\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u0430\u0440\u0442\u0443 \u0447\u0430\u043d\u043a\u0430 \u0438\u0437 \u0442\u0430\u0439\u043b\u043e\u0432, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043a\u0430\u0440\u0442\u0443 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0447\u0430\u043d\u043a\u0430 \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 [1,1] *\/ func NewChunk(idChunk Coordinate) Chunk { \tfmt.Println(&quot;New Chank&quot;, idChunk) \tchunk := Chunk{ChunkID: [2]int{idChunk.X, idChunk.Y}} \tvar chunkXMax, chunkYMax int \tvar chunkMap map[Coordinate]Tile \tchunkMap = make(map[Coordinate]Tile) \tchunkXMax = idChunk.X * CHUNK_SIZE \tchunkYMax = idChunk.Y * CHUNK_SIZE  \tswitch { \tcase chunkXMax &lt; 0 &amp;&amp; chunkYMax &lt; 0: \t\t{ \t\t\tfor x := chunkXMax + CHUNK_SIZE; x &gt; chunkXMax; x -= TILE_SIZE { \t\t\t\tfor y := chunkYMax + CHUNK_SIZE; y &gt; chunkYMax; y -= TILE_SIZE {  \t\t\t\t\tposX := float32(x - (TILE_SIZE \/ 2)) \t\t\t\t\tposY := float32(y + (TILE_SIZE \/ 2)) \t\t\t\t\ttile := Tile{} \t\t\t\t\ttile.X = int(posX) \t\t\t\t\ttile.Y = int(posY) \t\t\t\t\tperlinValue := PerlinNoise.Noise(posX\/PERLIN_SEED, posY\/PERLIN_SEED) \t\t\t\t\tswitch { \t\t\t\t\tcase perlinValue &lt; -0.01: \t\t\t\t\t\ttile.Key = &quot;Water&quot; \t\t\t\t\tcase perlinValue &gt;= -0.01 &amp;&amp; perlinValue &lt; 0: \t\t\t\t\t\ttile.Key = &quot;Sand&quot; \t\t\t\t\tcase perlinValue &gt;= 0 &amp;&amp; perlinValue &lt;= 0.5: \t\t\t\t\t\ttile.Key = &quot;Ground&quot; \t\t\t\t\tcase perlinValue &gt; 0.5: \t\t\t\t\t\ttile.Key = &quot;Mount&quot; \t\t\t\t\t} \t\t\t\t\tchunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile  \t\t\t\t} \t\t\t} \t\t} \tcase chunkXMax &lt; 0: \t\t{ \t\t\tfor x := chunkXMax + CHUNK_SIZE; x &gt; chunkXMax; x -= TILE_SIZE { \t\t\t\tfor y := chunkYMax - CHUNK_SIZE; y &lt; chunkYMax; y += TILE_SIZE { \t\t\t\t\tposX := float32(x - (TILE_SIZE \/ 2)) \t\t\t\t\tposY := float32(y + (TILE_SIZE \/ 2)) \t\t\t\t\ttile := Tile{} \t\t\t\t\ttile.X = int(posX) \t\t\t\t\ttile.Y = int(posY) \t\t\t\t\tperlinValue := PerlinNoise.Noise(posX\/PERLIN_SEED, posY\/PERLIN_SEED) \t\t\t\t\tswitch { \t\t\t\t\tcase perlinValue &lt; -0.12: \t\t\t\t\t\ttile.Key = &quot;Water&quot; \t\t\t\t\tcase perlinValue &gt;= -0.12 &amp;&amp; perlinValue &lt;= 0.5: \t\t\t\t\t\ttile.Key = &quot;Ground&quot; \t\t\t\t\tcase perlinValue &gt; 0.5: \t\t\t\t\t\ttile.Key = &quot;Mount&quot; \t\t\t\t\t} \t\t\t\t\tchunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile \t\t\t\t} \t\t\t} \t\t} \tcase chunkYMax &lt; 0: \t\t{ \t\t\tfor x := chunkXMax - CHUNK_SIZE; x &lt; chunkXMax; x += TILE_SIZE { \t\t\t\tfor y := chunkYMax + CHUNK_SIZE; y &gt; chunkYMax; y -= TILE_SIZE { \t\t\t\t\tposX := float32(x + (TILE_SIZE \/ 2)) \t\t\t\t\tposY := float32(y - (TILE_SIZE \/ 2)) \t\t\t\t\ttile := Tile{} \t\t\t\t\ttile.X = int(posX) \t\t\t\t\ttile.Y = int(posY) \t\t\t\t\tperlinValue := PerlinNoise.Noise(posX\/PERLIN_SEED, posY\/PERLIN_SEED) \t\t\t\t\tswitch { \t\t\t\t\tcase perlinValue &lt; -0.12: \t\t\t\t\t\ttile.Key = &quot;Water&quot; \t\t\t\t\tcase perlinValue &gt;= -0.12 &amp;&amp; perlinValue &lt;= 0.5: \t\t\t\t\t\ttile.Key = &quot;Ground&quot; \t\t\t\t\tcase perlinValue &gt; 0.5: \t\t\t\t\t\ttile.Key = &quot;Mount&quot; \t\t\t\t\t} \t\t\t\t\tchunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile  \t\t\t\t} \t\t\t} \t\t} \tdefault: \t\t{ \t\t\tfor x := chunkXMax - CHUNK_SIZE; x &lt; chunkXMax; x += TILE_SIZE { \t\t\t\tfor y := chunkYMax - CHUNK_SIZE; y &lt; chunkYMax; y += TILE_SIZE { \t\t\t\t\tposX := float32(x + (TILE_SIZE \/ 2)) \t\t\t\t\tposY := float32(y + (TILE_SIZE \/ 2)) \t\t\t\t\ttile := Tile{} \t\t\t\t\ttile.X = int(posX) \t\t\t\t\ttile.Y = int(posY) \t\t\t\t\tperlinValue := PerlinNoise.Noise(posX\/PERLIN_SEED, posY\/PERLIN_SEED) \t\t\t\t\tswitch { \t\t\t\t\tcase perlinValue &lt; -0.12: \t\t\t\t\t\ttile.Key = &quot;Water&quot; \t\t\t\t\tcase perlinValue &gt;= -0.12 &amp;&amp; perlinValue &lt;= 0.5: \t\t\t\t\t\ttile.Key = &quot;Ground&quot; \t\t\t\t\tcase perlinValue &gt; 0.5: \t\t\t\t\t\ttile.Key = &quot;Mount&quot; \t\t\t\t\t} \t\t\t\t\tchunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile  \t\t\t\t} \t\t\t} \t\t}  \t} \tchunk.Map = chunkMap \treturn chunk } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 json \u043a\u043b\u044e\u0447\u0438 \u043a \u043d\u0430\u0448\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u043c \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0447\u0430\u043d\u043a\u0430<br \/>  \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a Map_Controller,   <\/p>\n<pre><code class=\"go\">package GameController  import ( \t&quot;encoding\/json&quot; \t&quot;exampleMMO\/Chunk&quot; \t&quot;fmt&quot; \t&quot;net\/http&quot; )  func Map_Handler(w http.ResponseWriter, r *http.Request) { \t\t\tc:= Chunk.NewChunk(Chunk.Coordinate{1,1}) \t\t\t js, e :=json.Marshal(c) \t\t\t if e!= nil { \t\t\t \tfmt.Println(e.Error()) \t\t\t } \t\t\t fmt.Println(string(js)) }<\/code><\/pre>\n<p>  \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u0432 main.go  <\/p>\n<pre><code class=\"go\">\thttp.HandleFunc(&quot;\/map&quot;, GameController.Map_Handler)<\/code><\/pre>\n<p>  \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 localhost:8080\/map<br \/>  \u0412\u044b\u0432\u043e\u0434 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435:  <\/p>\n<pre><code class=\"bash\">New Chank {1 1} json: unsupported type: map[Chunk.Coordinate]Chunk.Tile <\/code><\/pre>\n<p>  \u0414\u0430, \u043c\u044b \u0437\u0430\u0431\u044b\u043b\u0438 \u0447\u0442\u043e \u0432 Golang \u043f\u0440\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043b\u044e\u0447\u0438 \u043a\u0430\u0440\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u043e\u0439. \u0414\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Go \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0442\u0438\u043f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 TextMarshaler, \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434 MarshalText(), \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 MarshalText() \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0438\u043f\u0430 Coordinate<br \/>  \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0432 Chunk.go \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434:  <\/p>\n<pre><code class=\"go\">func (t Coordinate) MarshalText() ([]byte, error) {  \treturn []byte(&quot;[&quot; + strconv.Itoa(t.X) + &quot;,&quot; + strconv.Itoa(t.Y) + &quot;]&quot;), nil }<\/code><\/pre>\n<p>  \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0441\u0430\u043c\u043e\u0435 \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u0447\u0442\u043e\u0431\u044b \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443. \u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0447\u0430\u043d\u043a\u0430\u043c\u0438 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0435\u0449\u0435 \u0440\u0430\u0437 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u044b\u0432\u043e\u0434 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xm\/cv\/fu\/xmcvfu0hilosymyu172rdgr2gjk.png\" alt=\"image\"><\/p>\n<p>  \u0414\u0430, \u0432\u0441\u0435 \u043e\u0442\u043b\u0438\u0447\u043d\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0432\u044b\u0432\u043e\u0434 \u0432 \u043f\u043e\u0442\u043e\u043a, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043a\u043e\u043d\u0446\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0434\u0432\u0435 \u0441\u0442\u0440\u043e\u0447\u043a\u0438:  <\/p>\n<pre><code class=\"go\"> \tw.Header().Set(&quot;Content-Type&quot;, &quot;application\/json&quot;) \tw.Write(js)<\/code><\/pre>\n<p>  \u041f\u043e\u043a\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0441 Golang \u0438 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0443. \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0442\u0440\u0438 \u0442\u0430\u0439\u0442\u043b\u0430, \u0445\u043e\u0442\u044f \u043f\u043e \u0444\u0430\u043a\u0442\u0443 \u0443 \u043d\u0430\u0441 \u0438\u0445 4, \u043d\u043e \u043d\u0430\u043c \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0445\u0432\u0430\u0442\u0438\u0442 \u0442\u0440\u0435\u0445, \u0430 \u0442\u043e \u0438 \u0434\u0432\u0443\u0445.<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/14\/ep\/mt\/14epmtlekh0tcaxqbyykzummptk.png\"><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/q6\/c3\/nw\/q6c3nwanc2id9a7-d770lxvrusu.png\"><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/of\/vf\/9v\/ofvf9vdoa0-dcuz-2smdbh5sx3i.png\"><br \/>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430\u0448\u0438 \u0442\u0430\u0439\u043b\u044b \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e Content \u0438 \u043d\u0430\u0447\u043d\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 MainScene.js, \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043d\u0430\u043c \u0445\u0432\u0430\u0442\u0438\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439   <\/p>\n<pre><code class=\"javascript\">class MainScene extends Phaser.Scene{ constructor() {     super({key: 'MainScene'})  } preload() {     \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043d\u0430\u0448\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0432 \u0438\u0433\u0440\u0443     this.load.image(&quot;Ground&quot;, &quot;Client\/Content\/sprGrass.png&quot;)     this.load.image(&quot;Water&quot;, &quot;Client\/Content\/sprWater1.png&quot;)     this.load.image(&quot;Sand&quot;, &quot;Client\/Content\/sprGrass.png&quot;)   } create() {     this.getGameMap() } update() {  } \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0430\u0440\u0442\u0443 \u0447\u0430\u043d\u043a\u0430 async getGameMap() {     let res = await fetch(&quot;\/map&quot;)     let result = await res.json()         this.drawChunk(result.map)  } \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043d\u0430\u0448\u0438 \u0442\u0430\u0439\u043b\u044b \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435 drawChunk(map) {     for (let chunkKey in map) {         this.add.image(map[chunkKey].x,map[chunkKey].y, map[chunkKey].key)     } }  }<\/code><\/pre>\n<p>  \u0421\u0435\u0440\u0432\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u0430\u043c \u043d\u0430\u0448 \u0447\u0430\u043d\u043a \u0432 \u0432\u0438\u0434\u0435 json \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0435\u0433\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/7t\/4u\/p4\/7t4up4ltauu_8d652po4svdvcae.png\" alt=\"image\"><br \/>  \u0410 \u0432\u043e\u0442 \u0442\u0430\u043a Phaser \u0435\u0433\u043e \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u043b \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 <br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/kd\/mr\/y8\/kdmry87ve-4eepdorxng_omh3h8.png\" alt=\"image\"><\/p>\n<p>  \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c, \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c 9 \u0447\u0430\u043d\u043a\u043e\u0432 \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u043c\u0438\u0440\u0443. \u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/github.com\/Lolodin\/HabrMMO\" rel=\"nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/488794\/\"> https:\/\/habr.com\/ru\/post\/488794\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/488794\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ra\/gk\/at\/ragkatgmqj9evur6anqx3rlos3e.gif\" alt=\"image\"><\/p>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0441 \u0432\u0430\u043c\u0438 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0443, \u0442\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u0443, \u043d\u0430 \u0447\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0448\u0430 \u0432\u0441\u0435\u043b\u0435\u043d\u043d\u0430\u044f, \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u044d\u0442\u043e \u0441\u043a\u0443\u0447\u043d\u043e \u0438 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043d\u0430\u0448\u0438\u0445 \u0442\u0430\u0439\u043b\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Phaser.js<\/p>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u043b \u0442\u0430\u043a:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/mb\/5r\/nh\/mb5rnhfwbge-ytwhwqk_hu9psrc.png\" alt=\"image\"><\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043d\u0430\u0434\u0435\u044e\u0441\u044c \u0443 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d Node.js \u0438 npm, \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0441\u0440\u043e\u0447\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435. \u0418 \u0442\u0430\u043a \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043c:  <\/p>\n<pre><code class=\"bash\">$ npm install phaser@3.22.0<\/code><\/pre>\n<p>  \u041f\u0440\u0438 \u0443\u0434\u0430\u0447\u043d\u043e\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:  <\/p>\n<pre><code class=\"bash\">+ phaser@3.22.0 added 15 packages from 48 contributors and audited 20 packages in 4.38s <\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/kv\/iq\/rd\/kviqrdtp_esg27iy8xdwi1o5mmu.png\" alt=\"image\"><br \/>  \u0422\u0430\u043a \u043e\u0442\u043b\u0438\u0447\u043d\u043e, \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043c\u043e\u0434\u0443\u043b\u0438, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hc\/jg\/bm\/hcjgbmqtqyh5s-yaagdgps8edxq.png\" alt=\"image\"><br \/>  \u0412 Content \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0438\u0433\u0440\u044b, \u0442.\u0435. \u043d\u0430\u0448\u0438 \u0441\u043f\u0440\u0430\u0439\u0442\u044b. \u0422\u0430\u043a \u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 game.js \u0438 MainScene.js, \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435(\u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u0444\u0430\u0439\u043b main.go) \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c index.html<br \/>  game.js \u2014 \u0445\u0440\u0430\u043d\u0438\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u0438\u0433\u0440\u044b<br \/>  MainScene.js \u2014 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b \u0438\u0433\u0440\u044b<br \/>  index.html \u2014 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440 \u0441\u0446\u0435\u043d\u044b<br \/>  \u0421\u0440\u0430\u0437\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0432 index.html \u043d\u0430\u0448\u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043c\u044b \u043a \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u043c  <\/p>\n<pre><code class=\"xml\">    &lt;script src=&quot;node_modules\/phaser\/dist\/phaser.js&quot; type=&quot;module&quot;&gt;&lt;\/script&gt;     &lt;script src=&quot;Client\/game.js&quot; type=&quot;module&quot;&gt;&lt;\/script&gt;<\/code><\/pre>\n<p>  \u0412 MainScene.js \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0430\u0448\u0435\u0439 \u0431\u0443\u0434\u0443\u0449\u0435\u0439 \u0441\u0446\u0435\u043d\u044b:  <\/p>\n<pre><code class=\"javascript\">export {MainScene} class MainScene extends Phaser.Scene{ constructor() {     super({key: 'MainScene'}) } preload() {  } create() {  } update() {  } }<\/code><\/pre>\n<p>  \u0412 game.js \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0442\u0438\u043f\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e \u0441\u0432\u043e\u0435\u043c\u0443 \u0432\u043a\u0443\u0441\u0443, \u0432\u043e\u0442 \u043c\u043e\u0438:  <\/p>\n<pre><code class=\"javascript\">import {MainScene} from &quot;.\/MainScene.js&quot;; let config = {     type: Phaser.AUTO,     width: 800,     height: 600,     disableContextMenu: true,     background: 'black',     physics: {         default: 'arcade',         arcadePhysics: {             overlapBias: 1         }     },     scene:[MainScene],     pixelArt: true,     roundPixels: true,     antialias: true  } let game = new Phaser.Game(config);<\/code><\/pre>\n<p>  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-298901","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/298901","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=298901"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/298901\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=298901"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=298901"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=298901"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}