{"id":359210,"date":"2024-05-21T00:27:54","date_gmt":"2024-05-21T00:27:54","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=359210"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-21T00:27:54","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=359210","title":{"rendered":"<span>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0445 \u0438\u0433\u0440 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Phaser3, React, Typescript<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u0443\u043c\u0430\u044e, \u043d\u0438 \u0434\u043b\u044f \u043a\u043e\u0433\u043e \u043d\u0435 \u0441\u0435\u043a\u0440\u0435\u0442, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0443\u0432\u0430\u0436\u0430\u044e\u0449\u0438\u0439 \u0441\u0435\u0431\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0432 \u0441\u0432\u043e\u0435\u043c \u043f\u043e\u0440\u0442\u0444\u043e\u043b\u0438\u043e \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u043f\u0435\u0442-\u043f\u0440\u043e\u0435\u043a\u0442, \u0430 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442, \u0434\u0430\u044e\u0449\u0438\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u043e\u043a. \u041f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u0438 \u0442\u0435\u043c\u0430\u0442\u0438\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432\u0435\u043b\u0438\u043a\u043e\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e, \u043d\u043e \u0441\u0440\u0435\u0434\u0438 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u2014 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0432\u043e\u0435\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0438\u0433\u0440\u044b.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/616\/2ce\/a0c\/6162cea0c55961ac0294bf4c5f32a0be.png\" width=\"1100\" height=\"550\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/616\/2ce\/a0c\/6162cea0c55961ac0294bf4c5f32a0be.png\"\/><\/figure>\n<h3>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0433\u0440<\/h3>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0433\u0440 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u0440\u0443\u0434\u043e\u0435\u043c\u043a\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043e\u043d \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u0437\u043d\u0430\u043d\u0438\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430, \u0442\u0430\u043a \u0438 \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u0438 \u0432\u0441\u0435\u0445 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e, \u0435\u0441\u043b\u0438 \u0440\u0435\u0447\u044c \u0438\u0434\u0435\u0442 \u043e \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u0430\u0445. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0447\u0430\u0441\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0434 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439 \u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u043c\u0438. \u041f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u0430\u0447\u0430\u0442\u044c \u0437\u043d\u0430\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438, \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438, \u0444\u0438\u0437\u0438\u043a\u0438. \u041d\u0430\u0432\u044b\u043a\u0438 \u0445\u0443\u0434\u043e\u0436\u043d\u0438\u043a\u0430, \u043f\u0443\u0441\u0442\u044c \u0438 \u0432 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u0431\u044a\u0435\u043c\u0435, \u0442\u043e\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0447\u0435\u043d\u044c \u043a\u0441\u0442\u0430\u0442\u0438. \u0410 \u0435\u0441\u043b\u0438 \u0438\u0433\u0440\u0430 \u0438\u043c\u0435\u0435\u0442 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u0443\u044e \u0446\u0435\u043b\u044c &#8212; \u0442\u043e \u0438 \u043c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433, \u0430\u043d\u0430\u043b\u0438\u0437 \u0440\u044b\u043d\u043a\u0430 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f. \u0412 \u0438\u0442\u043e\u0433\u0435, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0433\u0440 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u043a\u0430\u0447\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0430\u0432\u044b\u043a\u0438 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e, \u0447\u0442\u043e \u043b\u044e\u0431\u043e\u0435 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430 \u0432 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u043e\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u043d\u0430\u0434 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0432\u0435\u0431 &#8212; \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043b\u0435\u0433\u043a\u043e\u0439 \u043f\u0440\u043e\u0433\u0443\u043b\u043a\u043e\u0439. \u0422\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u0441 \u0438\u0433\u0440\u043e\u0439 \u0432 \u043f\u043e\u0440\u0442\u0444\u043e\u043b\u0438\u043e \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0440\u0435\u0434\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u043e\u0432 \u043d\u0430 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438. \u0411\u044b\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c \u0438\u0433\u0440 &#8212; \u0432\u0435\u0441\u0435\u043b\u043e \u0438 \u043a\u0440\u0443\u0442\u043e.<\/p>\n<h3>\u0421 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c?<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/567\/90c\/093\/56790c093420c4a0e83d022847744ac0.png\" width=\"700\" height=\"437\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/567\/90c\/093\/56790c093420c4a0e83d022847744ac0.png\"\/><\/figure>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0430\u044f \u0438\u0433\u0440\u0430 &#8212; \u0434\u043e\u0441\u0442\u043e\u0439\u043d\u0430\u044f \u0438\u0434\u0435\u044f, \u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u0432 \u043d\u043e\u0433\u0443 \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0438 \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044c \u0441\u0432\u044f\u0437\u043a\u0443:<\/p>\n<ul>\n<li>\n<p>Typescript<\/p>\n<\/li>\n<li>\n<p>React<\/p>\n<\/li>\n<li>\n<p>Webpack<\/p>\n<\/li>\n<li>\n<p>HTML\/CSS<\/p>\n<\/li>\n<li>\n<p>Phaser3<\/p>\n<\/li>\n<\/ul>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043f\u043e\u043c\u0438\u043c\u043e \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043d\u0430\u0432\u044b\u043a\u043e\u0432 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u0424\u0438\u0437\u0438\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043d\u043e\u0439 \u0433\u0440\u0430\u0444\u0438\u043a\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0428\u043a\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432 \u0432\u043f\u043e\u043b\u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0445\u0443\u0434\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0441\u043f\u0440\u0430\u0439\u0442\u044b, \u043c\u043e\u0434\u0435\u043b\u0438 \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440 \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 warcraft 2. <strong>\u0412\u0441\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u0438\u0445 \u0446\u0435\u043b\u044f\u0445.<\/strong><\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e4c\/0f4\/ece\/e4c0f4eceb7bbaa50f41226f06d96a26.png\" alt=\"\u041a\u0430\u0434\u0440 \u0438\u0437 \u0438\u0433\u0440\u044b warcraft 2\" title=\"\u041a\u0430\u0434\u0440 \u0438\u0437 \u0438\u0433\u0440\u044b warcraft 2\" width=\"448\" height=\"448\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e4c\/0f4\/ece\/e4c0f4eceb7bbaa50f41226f06d96a26.png\"\/><\/p>\n<div><figcaption>\u041a\u0430\u0434\u0440 \u0438\u0437 \u0438\u0433\u0440\u044b warcraft 2<\/figcaption><\/div>\n<\/figure>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 Phaser3?<\/h2>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f6d\/f76\/0ae\/f6df760aef2784932c3fa0a32ae9cb73.png\" width=\"700\" height=\"393\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f6d\/f76\/0ae\/f6df760aef2784932c3fa0a32ae9cb73.png\"\/><\/figure>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u044d\u0442\u043e \u0441\u0430\u043c\u044b\u0439 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0438\u0439\u0441\u044f open-source \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0445 \u0438\u0433\u0440 \u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 JavaScript\/TypeScript<\/p>\n<h3>\u041a\u0430\u043a\u0438\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u0430\u0448\u0438 \u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0430?<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1c6\/2a3\/4ef\/1c62a34efa2884deae697fad0e19d8f2.png\" width=\"700\" height=\"400\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1c6\/2a3\/4ef\/1c62a34efa2884deae697fad0e19d8f2.png\"\/><\/figure>\n<p><a href=\"https:\/\/phaser.io\/?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/phaser.io<\/a><\/p>\n<p><a href=\"https:\/\/labs.phaser.io\/?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/labs.phaser.io<\/a><\/p>\n<p>\u041d\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445 Phaser \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0431\u0435\u0441\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u043e\u0434\u0430, \u0438\u0433\u0440 \u0438 best-\u043f\u0440\u0430\u043a\u0442\u0438\u043a. \u0422\u0430\u043a\u0436\u0435 \u0441\u0440\u0435\u0434\u0438 \u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432: \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u043d\u043e\u0432\u044b\u0435 \u0444\u0438\u0447\u0438, \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043c\u044c\u044e\u043d\u0438\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043e\u0442\u043a\u0440\u044b\u0442\u0430\u044f \u0438 \u043f\u043e\u043b\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043a\u043d\u0438\u0433\u0438 \u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044f \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 Richard Davey <strong><a class=\"mention\" href=\"\/users\/photonstorm\">@photonstorm<\/a><\/strong><\/p>\n<h3>\u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0430<\/h3>\n<p><a href=\"https:\/\/github.com\/tfkfan\/phaser3-game-demo?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/tfkfan\/phaser3-game-demo<\/a><\/p>\n<p>\u0412\u044b\u0448\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0434\u0435\u043c\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. <\/p>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0435\u043c\u043e \u043b\u0435\u0436\u0438\u0442 \u0441\u0442\u0430\u0440\u0442\u0435\u0440 <a href=\"https:\/\/github.com\/tfkfan\/phaser3-react-template\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/tfkfan\/phaser3-react-template<\/a><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<\/p>\n<p><strong>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f: NodeJS >= v20, NPM >= v10<\/strong><\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c:<\/p>\n<pre><code>npm install npm start<\/code><\/pre>\n<p>\u0414\u0435\u043c\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 2 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435, \u043d\u043e \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043b\u0430\u0434\u044f\u0449\u0438\u0435 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c, \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 &#8212; React \u0438 Phaser. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c, \u0432 <em>Index.html <\/em>\u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043e \u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0432\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e:<\/p>\n<pre><code class=\"javascript\">&lt;div id=\"root\" class=\"app-container\"> ....  &lt;div id=\"game-root\"><\/code><\/pre>\n<p>\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0447\u0442\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 React \u0441 id =&#187;root&#187; \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u043c, \u043d\u0430 \u043d\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u0432\u0441\u0435 UI \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0431\u043b\u043e\u043a \u0441 z-index \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u043e\u0442 \u043d\u0443\u043b\u044f(\u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 UI \u043f\u043e\u0432\u0435\u0440\u0445 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d), \u043d\u0435\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0432 \u0432\u0435\u0440\u0441\u0442\u043a\u0435. \u0412 \u0431\u043b\u043e\u043a\u0435 id=&#187;game-root&#187; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e canvas, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u043f\u0440\u0438\u043b\u0435\u043f\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u043a \u0432\u0435\u0440\u043d\u0435\u043c\u0443 \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c.<\/p>\n<p>\u041b\u044e\u0431\u0430\u044f Phaser \u0438\u0433\u0440\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p>\n<p><em>phaser-game.ts <\/em>:<\/p>\n<pre><code class=\"javascript\">const config = {   type: Phaser.WEBGL, \/\/ \u0422\u0438\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f - WEBGL\/CANVAS   parent: 'game-root',   canvas: document.getElementById('game-canvas') as HTMLCanvasElement,   width: window.innerWidth ,   height: window.innerHeight,   pixelArt: true,   scene: [BootstrapScene, GameScene],   physics: {  \/\/ \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0434\u0432\u0438\u0436\u043a\u0430     default: 'arcade',     arcade: {       debug: false     }   } }<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0432\u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435, \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b, \u043d\u043e \u0441\u0430\u043c\u044b\u0439 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u044d\u0442\u043e \u043d\u0430\u0431\u043e\u0440 \u0441\u0446\u0435\u043d:<\/p>\n<p><strong>scene: [BootstrapScene, GameScene]<\/strong><\/p>\n<p>\u0421\u0446\u0435\u043d\u044b &#8212; \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e, \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u0432\u0441\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0432 \u0438\u0433\u0440\u0435. \u041f\u0435\u0440\u0432\u0430\u044f \u0438\u0437 \u043d\u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u0430. \u0412\u0441\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0435 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0446\u0435\u043d\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0445. \u0420\u0435\u0441\u0443\u0440\u0441\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435, \u044d\u0442\u043e \u0438 \u0441\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442\u044b, \u0438 \u0430\u0442\u043b\u0430\u0441\u044b \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439, \u0438 \u0437\u0432\u0443\u043a\u043e\u0432\u044b\u0435 \u0444\u0430\u0439\u043b\u044b, Tilemap-\u0444\u0430\u0439\u043b\u044b, \u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0438 \u043f\u0440.<\/p>\n<p>\u041b\u044e\u0431\u0430\u044f \u0441\u0446\u0435\u043d\u0430 \u0438\u043c\u0435\u0435\u0442 4 \u0432\u0430\u0436\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0438\u0437\u043c\u0435\u043d\u044f\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u043c\u043e\u0436\u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439:<\/p>\n<ul>\n<li>\n<p><strong><em>preload<\/em><\/strong> &#8212; \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0438 \u044d\u0442\u043e \u0432\u0441\u0435.<\/p>\n<\/li>\n<li>\n<p><strong><em>init<\/em><\/strong> &#8212; \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u043e\u043c. \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0446\u0435\u043d\u044b, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0438\u0433\u0440\u043e\u0432\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<\/li>\n<li>\n<p><strong><em>create<\/em><\/strong> &#8212; \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u0438\u0445 \u043a \u0441\u0446\u0435\u043d\u0435.<br \/> \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0432 \u044d\u0442\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435.<br \/> \u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043e\u043d\u0438 \u0441\u0430\u043c\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u0446\u0438\u043a\u043b\u0435.<\/p>\n<\/li>\n<li>\n<p><strong><em>update<\/em><\/strong> &#8212; \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0446\u0438\u043a\u043b. \u0417\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u043a\u043e\u0433\u0434\u0430 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 <strong>create<\/strong> \u0443\u0436\u0435 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447 \u044d\u0442\u043e\u0439 \u0441\u0446\u0435\u043d\u044b.<\/p>\n<pre><code class=\"javascript\">export default class BootstrapScene extends Phaser.Scene {     constructor() {         super('bootstrap')     }      init() {         store.dispatch(setLoading(true))     }      preload() {         this.load.on(Phaser.Loader.Events.PROGRESS, (value: number) => {             CONTROLS.setProgress(100 * value);         });         this.load.tilemapTiledJSON('worldmap', '.\/assets\/maps\/new\/map01merged.json');         this.load.image('tiles', '.\/assets\/maps\/new\/tiles.png');         this.load.atlas('mage', '.\/assets\/playersheets\/mage.png', '.\/assets\/playersheets\/mage.json');         this.load.image('fireball', '.\/assets\/skillsheets\/fire_002.png');         this.load.spritesheet('buff', '.\/assets\/skillsheets\/cast_001.png', {frameWidth: 192, frameHeight: 192});         this.load.image('face', '.\/assets\/images\/face.png');         this.load.spritesheet('fireballBlast', '.\/assets\/skillsheets\/s001.png', {frameWidth: 192, frameHeight: 192});         this.load.audio('intro', ['.\/assets\/music\/phaser-quest-intro.ogg']);         this.load.glsl('fireball_shader', '.\/assets\/shaders\/fireball_shader.frag');     }      create() {         CONTROLS.setProgress(100);         store.dispatch(setLoading(false))          this.sound.add('intro').play({             seek: 2.550         });          this.add.shader('fireball_shader', window.innerWidth\/2, window.innerHeight\/2, window.innerWidth ,window.innerHeight);     } }<\/code><\/pre>\n<p>\u0421\u0446\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u0432\u044b\u0432\u043e\u0434\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f React \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 <em>CONTROLS, <\/em>\u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0434\u043d\u0435\u0435<em>. <\/em>\u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u044f \u043c\u0443\u0437\u044b\u043a\u0438 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435:<\/p>\n<pre><code class=\"javascript\">this.sound.add('intro').play({             seek: 2.550 });<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/018\/451\/c23\/018451c2399902b2228100c40d6d3173.png\" alt=\"\u0412\u0445\u043e\u0434\u043d\u0430\u044f \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430. \u041d\u0430 \u0437\u0430\u0434\u043d\u0435\u043c \u043f\u043b\u0430\u043d\u0435 - \u0448\u0435\u0439\u0434\u0435\u0440\" title=\"\u0412\u0445\u043e\u0434\u043d\u0430\u044f \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430. \u041d\u0430 \u0437\u0430\u0434\u043d\u0435\u043c \u043f\u043b\u0430\u043d\u0435 - \u0448\u0435\u0439\u0434\u0435\u0440\" width=\"700\" height=\"421\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/018\/451\/c23\/018451c2399902b2228100c40d6d3173.png\"\/><\/p>\n<div><figcaption>\u0412\u0445\u043e\u0434\u043d\u0430\u044f \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430. \u041d\u0430 \u0437\u0430\u0434\u043d\u0435\u043c \u043f\u043b\u0430\u043d\u0435 &#8212; \u0448\u0435\u0439\u0434\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u0432\u0435\u0441\u044c \u0433\u0435\u0439\u043c\u043f\u043b\u0435\u0439 &#8212; <strong><em>GameScene.<\/em><\/strong><\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <strong><em>create:<\/em><\/strong><\/p>\n<pre><code class=\"javascript\">create() {         CONTROLS.setVersion(`Phaser v${Phaser.VERSION}`)         this.input.keyboard.on(Phaser.Input.Keyboard.Events.ANY_KEY_DOWN, (evt: { key: string; }) => {             this.player.setSkillIndex(this.skillIndexMap[evt.key])             const direction = this.keymap[evt.key]             if (direction)                 this.player.walk(direction, true)         });         this.input.keyboard.on(Phaser.Input.Keyboard.Events.ANY_KEY_UP, (evt: { key: string; }) => {             const direction = this.keymap[evt.key]             if (direction)                 this.player.walk(direction, false)         });          this.input.on(Phaser.Input.Events.POINTER_DOWN, (evt: {             worldX: number;             worldY: number;         }) => this.player.attack(new Vector2(evt.worldX, evt.worldY)));          this.createAnimations()         this.displayMap()         this.createPlayer()         this.cameras.main.startFollow(this.player)          \/\/ examples          \/\/ Animation\/Sprite         this.anims.create({             key: 'explosion',             frames: this.anims.generateFrameNumbers('fireballBlast', {start: 0, end: 19, first: 0}),             frameRate: 20,             repeat: -1         })          this.add.sprite(2500, 1100, \"\").play('explosion')          \/\/ Arcade Physics \/ collision          const items = this.add.group([this.createItem()])         this.physics.add.collider(this.player, items, (object1: Phaser.Tilemaps.Tile | Phaser.GameObjects.GameObject, object2: Phaser.Tilemaps.Tile | Phaser.GameObjects.GameObject) => {             object2.destroy(true)             setTimeout(() => {                 items.add(this.createItem(), true)             }, 3000)         })    }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439, \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0438 \u043c\u043d\u043e\u0433\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0441\u043f\u0440\u0430\u0439\u0442\u044b.<\/p>\n<p>\u0421\u043f\u0440\u0430\u0439\u0442 &#8212; \u044d\u0442\u043e \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u043d\u044b\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 &#171;\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440&#187; \u0442\u0435\u043a\u0441\u0442\u0443\u0440 \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438: \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435, \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438, \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0438 \u0434\u0440. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"javascript\">export default class Face extends Phaser.Physics.Arcade.Sprite {     constructor(scene: Scene, x: number, y: number) {         \/\/ \u0421\u0446\u0435\u043d\u0430, \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b, \u043a\u043b\u044e\u0447 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b         super(scene, x, y, 'face');         \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a \u0444\u0438\u0437\u0438\u043a\u0435         this.scene.physics.add.existing(this)         \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a \u0441\u0446\u0435\u043d\u0435         this.scene.add.existing(this)     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0442\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u0430\u0434\u0440\u043e\u0432 \u0438 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0435\u0435 \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/123\/680\/f53\/123680f53e94c545fd7abaf550d5f96c.png\" alt=\"\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442\" title=\"\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442\" width=\"700\" height=\"560\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/123\/680\/f53\/123680f53e94c545fd7abaf550d5f96c.png\"\/><\/p>\n<div><figcaption>\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0432\u0437\u0440\u044b\u0432\u0430 \u0438\u0437 20 \u043d\u0430\u0440\u0435\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0432\u0435\u0440\u0445\u0443-\u0432\u043d\u0438\u0437, \u0441\u043b\u0435\u0432\u0430-\u043d\u0430\u043f\u0440\u0430\u0432\u043e \u043a\u0430\u0434\u0440\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b <em>fireballBlast<\/em>:<\/p>\n<pre><code class=\"javascript\">this.anims.create({             key: 'explosion',             frames: this.anims.generateFrameNumbers('fireballBlast', {start: 0, end: 19, first: 0}),             frameRate: 20,             repeat: -1 })<\/code><\/pre>\n<p>\u0428\u0438\u0440\u0438\u043d\u0430 \u0438 \u0432\u044b\u0441\u043e\u0442\u0430 \u043a\u0430\u0434\u0440\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043b\u044e\u0447 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0438\u0437 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0446\u0435\u043d\u0435:<\/p>\n<pre><code class=\"javascript\">this.load.spritesheet('fireballBlast', '.\/assets\/skillsheets\/s001.png', {frameWidth: 192, frameHeight: 192});<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043f\u0440\u0430\u0439\u0442 \u0432 \u0442\u043e\u0447\u043a\u0435 (2500, 1100) \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e &#171;<em>explosion<\/em>&#187; \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <strong>play<\/strong><\/p>\n<pre><code>this.add.sprite(2500, 1100, \"\").play('explosion')<\/code><\/pre>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/71d\/8c5\/941\/71d8c594114f3a643f8f0ef41d40e598.png\" alt=\"\u0412\u0437\u0440\u044b\u0432\" title=\"\u0412\u0437\u0440\u044b\u0432\" width=\"310\" height=\"249\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/71d\/8c5\/941\/71d8c594114f3a643f8f0ef41d40e598.png\"\/><\/p>\n<div><figcaption>\u0412\u0437\u0440\u044b\u0432<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <em>this.createPlayer()<\/em><\/p>\n<pre><code class=\"javascript\">createPlayer(): Mage {         return this.player = new Mage(this, 2100, 1000, store.getState().application.nickname) }<\/code><\/pre>\n<p>\u0413\u0434\u0435 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0430 Mage<\/p>\n<pre><code class=\"javascript\">export default class Mage extends Player {     private skillFactory: SkillFactory = new SkillFactory(); \/\/ Factory \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0443\u043c\u0435\u043d\u0438\u0439     private skills = [\"Fireball\", \"Buff\"] \/\/ \u0412\u0441\u0435\u0433\u043e 2 \u0443\u043c\u0435\u043d\u0438\u044f     private currentSkillIndex = 0 \/\/ \u0418\u043d\u0434\u0435\u043a\u0441 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0443\u043c\u0435\u043d\u0438\u044f      constructor(scene: Scene, x: number, y: number, name:string) {         super(scene, x, y, \"mage\", name);         \/\/\u0421\u0446\u0435\u043d\u0430, \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0438\u0433\u0440\u043e\u043a\u0430, \u043a\u043b\u044e\u0447 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b, \u0438\u043c\u044f     }     \/\/ \u0418\u0437\u043c\u0435\u043d\u0438\u0439 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0443\u043c\u0435\u043d\u0438\u0435     public setSkillIndex(index: number) {         if (index === undefined || index &lt; 0 || index > 1)             return         CONTROLS.setSkill(index)         this.currentSkillIndex = index     }     \/\/ \u041a\u0430\u0441\u0442\u043e\u0432\u0430\u0442\u044c \u0443\u043c\u0435\u043d\u0438\u0435 \u043f\u043e \u0446\u0435\u043b\u0438     override attack(target: Vector2) {         this.skillFactory.create(this.scene, this.x, this.y, target, this.skills[this.currentSkillIndex])         super.attack(target)     } }<\/code><\/pre>\n<p>\u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u043d \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 Player \u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<br \/> \u0434\u0432\u0438\u0436\u0443\u0449\u0435\u0433\u043e\u0441\u044f \u0438 \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0432 8 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445(\u0432\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442<br \/> \u043d\u0430\u0436\u0430\u0442\u043e\u0439 \u043a\u043b\u0430\u0432\u0438\u0448\u0438)<\/p>\n<pre><code class=\"javascript\">\/\/Phaser.Physics.Arcade.Sprite - \u043a\u043b\u0430\u0441\u0441 \u0441\u043f\u0440\u0430\u0439\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0432 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0434\u0432\u0438\u0436\u043a\u0435 \u0438 \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b export default abstract class Player extends Phaser.Physics.Arcade.Sprite {      private animationKey: string;     private attackAnimationKey: string;     public isMoving: boolean;     public isAttack: boolean;     public name: string;     public target: Vector2;     private nameHolder: Phaser.GameObjects.Text;     private directionState: Map&lt;Direction, boolean> = new Map([         [Direction.RIGHT, false],         [Direction.UP, false],         [Direction.DOWN, false],         [Direction.LEFT, false]     ]);     private directionVerticalVelocity: Map&lt;Direction, number> = new Map([         [Direction.UP, -GameConfig.playerAbsVelocity],         [Direction.DOWN, GameConfig.playerAbsVelocity]     ])     private directionHorizontalVelocity: Map&lt;Direction, number> = new Map([         [Direction.RIGHT, GameConfig.playerAbsVelocity],         [Direction.LEFT, -GameConfig.playerAbsVelocity]     ])      protected constructor(scene: Scene, x: number, y: number, textureKey: string, name: string) {         super(scene, x, y, textureKey);         this.name = name;         this.init();     }      private init() {         this.isMoving = false;         this.isAttack = false;         this.animationKey = Direction.UP;         this.scene.physics.add.existing(this)         this.scene.add.existing(this);          this.nameHolder = this.scene.add.text(0, 0, this.name, {             font: '14px pixel',             stroke: \"#ffffff\",             strokeThickness: 2         }).setOrigin(0.5);     }      attack(target: Vector2) {         this.isAttack = true         this.target = target         this.attackAnimationKey = `${this.animationKey}attack`          this.play(this.attackAnimationKey);         this.on(Phaser.Animations.Events.ANIMATION_COMPLETE, () => {             this.isAttack = false;             this.handleMovingAnimation()         }, this);     }      walk(direction: Direction, state: boolean) {         if (this.directionState.get(direction) === state)             return;          this.directionState.set(direction, state)         const vec = [0, 0]         const activeState = Array.from(this.directionState.entries())             .filter(value => value[1])             .map(value => {                 if (this.directionVerticalVelocity.has(value[0])) {                     vec[1] = this.directionVerticalVelocity.get(value[0])                 } else if (this.directionHorizontalVelocity.has(value[0]))                     vec[0] = this.directionHorizontalVelocity.get(value[0])                 return value[0]             })         this.isMoving = activeState.length > 0          if (activeState.length === 1)             this.animationKey = activeState[0]         else if (activeState.length === 2)             this.animationKey = activeState[1] + activeState[0]          this.setVelocity(vec[0], vec[1])          this.handleMovingAnimation()     }      private handleMovingAnimation() {         if (this.isAttack)             return;         if (this.isMoving)             this.play(this.animationKey);         else {             this.play(this.animationKey);             this.stop()         }     }      override preUpdate(time, delta): void {         super.preUpdate(time, delta);         this.nameHolder.setPosition(this.x, this.y - 30);     } }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/246\/8f0\/ffc\/2468f0ffce41a6bf3a402cec510a2fba.png\" alt=\"\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442 \u043c\u0430\u0433\u0430\" title=\"\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442 \u043c\u0430\u0433\u0430\" width=\"670\" height=\"700\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/246\/8f0\/ffc\/2468f0ffce41a6bf3a402cec510a2fba.png\"\/><\/p>\n<div><figcaption>\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442 \u043c\u0430\u0433\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0432\u043e \u0432\u0441\u0435\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0438 \u0443\u043c\u0435\u043d\u0438\u0439 \u043f\u043e \u0441\u043f\u0440\u0430\u0439\u0442\u0430\u043c:<\/p>\n<pre><code class=\"javascript\">createAnimations() {         GameConfig.playerAnims.map((key) => ({             key,             frames: this.anims.generateFrameNames(\"mage\", {                 prefix: key,                 start: 0,                 end: 4             }),             frameRate: 8,             repeat: !key.includes(\"attack\") &amp;&amp; !key.includes(\"death\") ? -1 : 0         })).concat([             {                 key: 'fireballBlast',                 frames: this.anims.generateFrameNumbers('fireballBlast', {start: 0, end: 19, first: 0}),                 frameRate: 20,                 repeat: 0             },             {                 key: 'buff',                 frames: this.anims.generateFrameNumbers('buff', {start: 0, end: 19, first: 0}),                 frameRate: 20,                 repeat: 0             }         ]).forEach((config) => this.anims.create(config));     }<\/code><\/pre>\n<p>\u0412 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0430\u0442\u043b\u0430\u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u043c\u0430\u0433\u0430 <em>mage.json, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u044b \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043a\u0430\u0434\u0440\u0430<\/em>:<\/p>\n<pre><code class=\"javascript\">\"frames\": {     \"up0\": {       \"frame\": {         \"x\": 0,         \"y\": 0,         \"w\": 75,         \"h\": 61       }     },     \"up1\": {       \"frame\": {         \"x\": 0,         \"y\": 61,         \"w\": 75,         \"h\": 61       }     },     \"up2\": {       \"frame\": {         \"x\": 0,         \"y\": 122,         \"w\": 75,         \"h\": 61       }     },     \"up3\": {       \"frame\": {         \"x\": 0,         \"y\": 183,         \"w\": 75,         \"h\": 61       }     },     \"up4\": {       \"frame\": {         \"x\": 0,         \"y\": 244,         \"w\": 75,         \"h\": 61       }     }, ....<\/code><\/pre>\n<p>Phaser \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u0433\u0430\u0442\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0432\u0432\u043e\u0434\u0430. \u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u0447\u043a\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u0432\u0435\u0441\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043b\u044e\u0431\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b:<\/p>\n<pre><code class=\"javascript\">this.input.keyboard.on(Phaser.Input.Keyboard.Events.ANY_KEY_DOWN, (evt: { key: string; }) => {             this.player.setSkillIndex(this.skillIndexMap[evt.key])             const direction = this.keymap[evt.key]             if (direction)                 this.player.walk(direction, true) });<\/code><\/pre>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441 \u043c\u044b\u0448\u044c\u044e, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043a\u043b\u0438\u043a\u0430:<\/p>\n<pre><code class=\"javascript\">this.input.on(Phaser.Input.Events.POINTER_DOWN, (evt: {             worldX: number;             worldY: number;  }) => this.player.attack(new Vector2(evt.worldX, evt.worldY)));<\/code><\/pre>\n<p>\u0423\u043c\u0435\u043d\u0438\u0435, \u0438\u043b\u0438 \u0432\u044b\u0441\u0442\u0440\u0435\u043b &#8212; \u0432\u0430\u0436\u043d\u0430\u044f \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u0438\u0433\u0440\u044b. \u042d\u0442\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u0442\u0430\u043a\u0436\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043f\u0440\u0430\u0439\u0442\u043e\u043c \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0435\u043a\u0441\u0442\u0443\u0440 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f. \u041c\u0435\u0442\u043e\u0434 <em>play<\/em> \u0442\u0430\u043a \u0438\u043b\u0438 \u0438\u043d\u0430\u0447\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u043d\u0443\u0436\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e.<\/p>\n<pre><code class=\"javascript\">export abstract class Skill extends Phaser.Physics.Arcade.Sprite {     protected target: Vector2;     protected initialPosition: Vector2;      private finallyAnimated = false;      protected constructor(scene: Phaser.Scene, x: number, y: number, image: string, target: Vector2) {         super(scene, x, y, image, 0);         this.scene.add.existing(this);         this.scene.physics.add.existing(this)         this.target = target;         this.initialPosition = new Vector2(x, y)         this.init()     }      protected preUpdate(time: number, delta: number) {         super.preUpdate(time, delta);         if (!this.finallyAnimated &amp;&amp; new Vector2(this.x, this.y).distance(this.target) &lt; GameConfig.skillCollisionDistance) {             this.finallyAnimated = true             this.setVelocity(0, 0)             this.animateFinally().then(sprite => this.destroy(true))                 .catch(e => this.destroy(true))         }     }      protected abstract playFinalAnimation(): void      animateFinally(): Promise&lt;Skill> {         return new Promise((resolve, reject) => {             try {                 this.on(Phaser.Animations.Events.ANIMATION_COMPLETE, (animation: Phaser.Animations.Animation) => {                     try {                         resolve(this)                     } catch (e) {                         reject(e)                     }                 }, this);                 this.playFinalAnimation()             } catch (e) {                 reject(e)             }         })     }      init(): void {         const vel = new Vector2(this.target.x - this.initialPosition.x, this.target.y - this.initialPosition.y).normalize()         this.setPosition(this.initialPosition.x, this.initialPosition.y)         this.setVelocity(vel.x * GameConfig.skillAbsVelocity, vel.y * GameConfig.skillAbsVelocity)     } }<\/code><\/pre>\n<p>\u041e\u0433\u043d\u0435\u043d\u043d\u044b\u0439 \u0448\u0430\u0440<\/p>\n<pre><code class=\"javascript\">export class Fireball extends Skill {     constructor(scene: Phaser.Scene, x: number, y: number, target: Vector2) {         super(scene, x, y, \"fireball\", target);     }      override init() {         super.init();         this.setScale(0.02, 0.02);     }      override playFinalAnimation() {         this.play(\"fireballBlast\");         this.setScale(1, 1)     } }<\/code><\/pre>\n<p>\u0411\u0430\u0444<\/p>\n<pre><code class=\"javascript\">export class Buff extends Skill {     constructor(scene: Phaser.Scene, x: number, y: number, target: Vector2) {         super(scene, x, y, \"buff\", target);     }      override playFinalAnimation() {         this.play(\"buff\");     }      override init(): void {         this.setPosition(this.initialPosition.x, this.initialPosition.y)     } }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6a9\/c9b\/cd9\/6a9c9bcd9395861aff53613e5df64d22.png\" alt=\"\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442 \u0431\u0430\u0444\u0430\" title=\"\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442 \u0431\u0430\u0444\u0430\" width=\"700\" height=\"560\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6a9\/c9b\/cd9\/6a9c9bcd9395861aff53613e5df64d22.png\"\/><\/p>\n<div><figcaption>\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442 \u0431\u0430\u0444\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0439 \u0432 \u0438\u0433\u0440\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0430\u0440\u043a\u0430\u0434\u043d\u043e\u0433\u043e \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0434\u0432\u0438\u0436\u043a\u0430.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u0435\u0434\u043c\u0435\u0442 &#8212; \u043b\u0438\u0446\u043e, \u043a\u0430\u043a \u0433\u0440\u0443\u043f\u043f\u0443 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432, \u0434\u043b\u044f \u0435\u0433\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e<br \/> \u0440\u0435\u0441\u043f\u0430\u0443\u043d\u0430 \u043f\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044e 3\u0445 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u043e\u0441\u043b\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0441 \u043d\u0438\u043c.<\/p>\n<pre><code class=\"javascript\">createItem(): Face {         return new Face(this, 2500, 1100) }<\/code><\/pre>\n<pre><code class=\"javascript\">\/\/ Arcade Physics \/ collision  const items = this.add.group([this.createItem()]) this.physics.add.collider(this.player, items, (object1: Phaser.Tilemaps.Tile | Phaser.GameObjects.GameObject, object2: Phaser.Tilemaps.Tile | Phaser.GameObjects.GameObject) => {             object2.destroy(true) \/\/ \u0423\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441\u043e \u0441\u0446\u0435\u043d\u044b \u043f\u0440\u0438 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438             setTimeout(() => {                 items.add(this.createItem(), true) \/\/ \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435             }, 3000) })<\/code><\/pre>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9d7\/88f\/a28\/9d788fa287136249938825ded6c2780e.png\" alt=\"\u041f\u0440\u0435\u0434\u043c\u0435\u0442\" title=\"\u041f\u0440\u0435\u0434\u043c\u0435\u0442\" width=\"383\" height=\"248\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d7\/88f\/a28\/9d788fa287136249938825ded6c2780e.png\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0435\u0434\u043c\u0435\u0442<\/figcaption><\/div>\n<\/figure>\n<h3>\u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044f<\/h3>\n<p>\u0418\u0433\u0440\u043e\u0432\u0430\u044f \u043a\u0430\u0440\u0442\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0444\u0430\u0439\u043b\u043e\u0432: <strong><em>map01merged.json, tiles.png, tiles.tsx<\/em><\/strong> ( <strong>\u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0441 typescript tsx \u0444\u0430\u0439\u043b\u043e\u043c<\/strong>).<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f &#8212; <strong>Tiled<\/strong>, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b\u0439 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043b\u044e\u0431\u044b\u0445, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438\u0437\u043e\u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0443\u0440\u043e\u0432\u043d\u0435\u0439, \u043a\u0430\u0440\u0442, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0442\u0430\u0439\u043b\u043e\u0432 \u0438 \u0442\u0430\u0439\u043b\u0441\u0435\u0442\u043e\u0432.<\/p>\n<p><a href=\"https:\/\/www.mapeditor.org\/\" rel=\"noopener noreferrer nofollow\">https:\/\/www.mapeditor.org<\/a><\/p>\n<p>\u0411\u043e\u0433\u0430\u0442\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 Tiled \u0432 Phaser \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0433\u0438\u0431\u043a\u043e \u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u0430\u043c\u0438\u043c\u0438 \u0442\u0430\u0439\u043b\u0430\u043c\u0438 \u043a\u0430\u0440\u0442\u044b &#8212; \u043a\u043b\u0435\u0442\u043a\u0430\u043c\u0438. \u0418\u0445 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c, \u0443\u0434\u0430\u043b\u044f\u0442\u044c, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0439 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441 \u043d\u0438\u043c\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6d4\/887\/066\/6d48870664a30162da385001ed6f2aa5.png\" alt=\"\u0422\u0430\u0439\u043b\u0441\u0435\u0442\" title=\"\u0422\u0430\u0439\u043b\u0441\u0435\u0442\" width=\"626\" height=\"659\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6d4\/887\/066\/6d48870664a30162da385001ed6f2aa5.png\"\/><\/p>\n<div><figcaption>\u0422\u0430\u0439\u043b\u0441\u0435\u0442<\/figcaption><\/div>\n<\/figure>\n<p>\u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043a\u0430\u0440\u0442\u044b \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439<\/p>\n<pre><code class=\"javascript\">displayMap() {         this.map = this.add.tilemap('worldmap');         const tileset = this.map.addTilesetImage('tiles', 'tiles');         for (let i = 0; i &lt; this.map.layers.length; i++)             this.map.createLayer(0, tileset, 0, 0).setVisible(true);     }<\/code><\/pre>\n<h3>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/h3>\n<p>\u041a\u0430\u043a \u044f \u0443\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043b, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438\u0433\u0440\u043e\u043a\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432\u0432\u043e\u0434\u0430 \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0435 React \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/401\/3cc\/05a\/4013cc05a89e79339887d313b831252e.png\" alt=\"\u041e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f\" title=\"\u041e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f\" width=\"286\" height=\"111\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/401\/3cc\/05a\/4013cc05a89e79339887d313b831252e.png\"\/><\/p>\n<div><figcaption>\u041e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u043b\u0435\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443 \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e:<\/p>\n<p>\u041e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439<\/p>\n<pre><code class=\"javascript\">const DebugPanel = () => {     const [fps, setFps] = useState(0);     const [version, setVersion] = useState('');     const [skill, setSkill] = useState(0);     CONTROLS.registerGameDebugControls({         setVersion,         setFps,         setSkill     })      return (         &lt;>             &lt;div>                 &lt;span >                     Fps: {fps}                 &lt;\/span>                 &lt;br>&lt;\/br>                 &lt;span >                     Version: {version}                 &lt;\/span>                 &lt;br>&lt;\/br>                 &lt;span >                     Current skill: {skill+1}                 &lt;\/span>             &lt;\/div>         &lt;\/>     ); };  export default DebugPanel;<\/code><\/pre>\n<p>\u0421\u0432\u044f\u0437\u0430\u0442\u044c \u0445\u0443\u043a\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c CONTROLS, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0432 \u0438\u0445<\/p>\n<pre><code class=\"javascript\">CONTROLS.registerGameDebugControls({         setVersion,         setFps,         setSkill     })<\/code><\/pre>\n<p>\u041e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440 \u0432 \u0444\u0430\u0439\u043b\u0435 <em>controls.ts<\/em><\/p>\n<pre><code class=\"javascript\">export type ValueSetter&lt;T> = (T) => void;  \/\/ Create your own react controls interface interface GameDebugControls {     setVersion: ValueSetter&lt;string>     setFps: ValueSetter&lt;number>     setSkill: ValueSetter&lt;number> }  interface GameLoaderControls {     setProgress: ValueSetter&lt;number> }  \/\/ Add your own react controls interface GameControlsMap {     debug?: GameDebugControls     loader?: GameLoaderControls }  class GameControls {     private controls: GameControlsMap = {}      \/\/ Create your own register controls method     public registerGameDebugControls(controls: GameDebugControls) {         this.controls.debug = controls     }      public registerGameLoaderControls(controls: GameLoaderControls) {         this.controls.loader = controls     }      \/\/ Create your own valueSetter method     public setFps(fps: number) {         if (checkExists(this.controls.debug))             this.controls.debug.setFps(fps)     }      public setSkill(skill: number) {         if (checkExists(this.controls.debug))             this.controls.debug.setSkill(skill)     }      public setVersion(version: string) {         if (checkExists(this.controls.debug))             this.controls.debug.setVersion(version)     }      public setProgress(progress: number) {         if (checkExists(this.controls.loader))             this.controls.loader.setProgress(progress)     } }  export const CONTROLS: GameControls = new GameControls()<\/code><\/pre>\n<p>\u0418 \u0441\u043f\u043e\u043a\u043e\u0439\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0437 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0441\u0446\u0435\u043d\u044b<\/p>\n<pre><code class=\"javascript\">CONTROLS.setVersion(`Phaser v${Phaser.VERSION}`) CONTROLS.setFps(Math.trunc(this.sys.game.loop.actualFps));<\/code><\/pre>\n<p>\u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u0444\u043e\u0440\u043c\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0438\u0433\u0440\u0443:<\/p>\n<pre><code class=\"javascript\">export const Login = () => {     const dispatch = useAppDispatch()      const onStart = (evt) => {         evt.preventDefault()         const data = new FormData(evt.target)         if(!data.get(\"name\")) {             alert(\"Name is required\")             return;         }         CONTROLS.setProgress(50)         dispatch(setLoading(true))         dispatch(setNickname(data.get(\"name\").toString()))         setTimeout(() => {             dispatch(setLoading(false))             dispatch(setCurrentPage(Page.GAME))             launchGame()         }, 3000)     };     return (         &lt;div className=\"center-extended\">             &lt;div className=\"fade-in\">                 &lt;Card className=\"game-form\">                     &lt;Form onSubmit={onStart} initialValues={{name: \"name\"}}>                         &lt;Input type=\"text\" placeholder=\"Input your name\" name='name'\/>                          &lt;Button type=\"submit\" color=\"success\">Start game!&lt;\/Button>                     &lt;\/Form>                 &lt;\/Card>             &lt;\/div>         &lt;\/div>     ); };  export default Login;<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c04\/192\/3b1\/c041923b1d54acdf6d8630ed65758913.png\" alt=\"\u0424\u043e\u0440\u043c\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0438\u0433\u0440\u0443\" title=\"\u0424\u043e\u0440\u043c\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0438\u0433\u0440\u0443\" width=\"700\" height=\"481\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c04\/192\/3b1\/c041923b1d54acdf6d8630ed65758913.png\"\/><\/p>\n<div><figcaption>\u0424\u043e\u0440\u043c\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0438\u0433\u0440\u0443<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u0431\u043b\u043e\u043a\u0443 React \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e &#171;pointer-events&#187;:<\/p>\n<pre><code class=\"javascript\">document.getElementById(\"root\").style.pointerEvents=\"none\"<\/code><\/pre>\n<p>\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e css-\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u0442\u0430\u043c, \u0433\u0434\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043b\u0438\u043a\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 (\u043a\u043d\u043e\u043f\u043a\u0438, \u0444\u043e\u0440\u043c\u044b \u0438 \u0442.\u0434.).<\/p>\n<h3>\u0412\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u044b<\/h3>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u0435\u043c\u043e \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u0438\u043c\u0438 \u0435\u0441\u0442\u044c \u0444\u0430\u0439\u043b <em>network.ts<\/em><\/p>\n<pre><code class=\"javascript\">class Network {     private socket: any;     private events: Map&lt;number, [any, OnMessageHandler]> = new Map&lt;number, [any, OnMessageHandler]>()      constructor() {         if (!window.WebSocket) {             \/\/ @ts-ignore             window.WebSocket = window.MozWebSocket;         }         if (window.WebSocket) {             this.socket = new WebSocket(\"ws:\/\/localhost:8085\/websocket\");         } else {             alert(\"Your browser does not support Web Socket.\");         }          this.socket.addEventListener('open', (event) => {             console.log(\"Connection established\");         });          this.socket.addEventListener('error', (event) => {             console.log(event.message);         });          this.socket.addEventListener('close', (event) => {             console.log(\"Web Socket closed\");         });          this.socket.addEventListener('message', (evt) => {             const eventData = JSON.parse(evt.data);             if (this.events.has(eventData.type)) {                 const arr = this.events.get(eventData.type)                 arr[1].call(arr[0], eventData.data);             }         });     }      public on(type: number, handler: OnMessageHandler, thisArg:any) {         this.events.set(type, [thisArg, handler]);     }      public send(type: number, data: any = null) {         if (this.socket.readyState !== WebSocket.OPEN) {             console.log(\"Socket is not ready\");             return;         }          this.socket.send(this.createEvent(type, data));     }      private createEvent = (eventType: number, payload: any = null) => {         const obj: any = {             type: eventType,             data: null         };         if (payload) {             obj.data = payload         }         return JSON.stringify(obj);     } }  export const network = new Network();<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 send \u0438\u0437 \u043b\u044e\u0431\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"javascript\">network.send(TYPE, JSON_OBJECT)<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"javascript\">network.on(TYPE, (data)=> {}, this)<\/code><\/pre>\n<h3>\u0418\u0442\u043e\u0433<\/h3>\n<p>\u0414\u0435\u043c\u043e \u0438\u0433\u0440\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u043e\u0434\u0440\u044b\u043c. \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043d\u0430\u0432\u044b\u043a\u0438 \u0432 \u0445\u043e\u0434\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0443\u0441\u0442\u044c \u0434\u0430\u0436\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0434\u0435\u043c\u043e &#8212; \u0431\u0435\u0441\u0446\u0435\u043d\u043d\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438\u0433\u0440\u044b, \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044f \u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fb2\/e55\/29d\/fb2e5529d396dea7a7706f1de10bcf58.png\" width=\"700\" height=\"408\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fb2\/e55\/29d\/fb2e5529d396dea7a7706f1de10bcf58.png\"\/><\/figure>\n<p><strong>\u0412 \u0441\u043a\u043e\u0440\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u0439\u0434\u0435\u0442 \u0441\u0442\u0430\u0442\u044c\u044f, \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0430\u044f backend \u043c\u0443\u043b\u0442\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u043e\u0432<\/strong><\/p>\n<p><strong>\u0414\u0435\u043b\u0438\u0442\u0435\u0441\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u043c \u0441 \u043a\u043e\u043b\u043b\u0435\u0433\u0430\u043c\u0438, \u043f\u0438\u0448\u0438\u0442\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u043d\u0430 \u043a\u0430\u043a\u0443\u044e \u0442\u0435\u043c\u0443 \u0445\u043e\u0442\u0435\u043b\u0438 \u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b<\/strong><\/p>\n<h3>\u0421\u0441\u044b\u043b\u043a\u0438<\/h3>\n<p><a href=\"https:\/\/github.com\/tfkfan\/phaser3-game-demo?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/tfkfan\/phaser3-game-demo<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/tfkfan\/phaser3-react-template?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/tfkfan\/phaser3-react-template<\/a><\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \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\/articles\/771630\/\"> https:\/\/habr.com\/ru\/articles\/771630\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u0443\u043c\u0430\u044e, \u043d\u0438 \u0434\u043b\u044f \u043a\u043e\u0433\u043e \u043d\u0435 \u0441\u0435\u043a\u0440\u0435\u0442, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0443\u0432\u0430\u0436\u0430\u044e\u0449\u0438\u0439 \u0441\u0435\u0431\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0432 \u0441\u0432\u043e\u0435\u043c \u043f\u043e\u0440\u0442\u0444\u043e\u043b\u0438\u043e \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u043f\u0435\u0442-\u043f\u0440\u043e\u0435\u043a\u0442, \u0430 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442, \u0434\u0430\u044e\u0449\u0438\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u043e\u043a. \u041f\u0440\u0435\u0434\u043c\u0435\u0442\u043d\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u0438 \u0442\u0435\u043c\u0430\u0442\u0438\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432\u0435\u043b\u0438\u043a\u043e\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e, \u043d\u043e \u0441\u0440\u0435\u0434\u0438 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u2014 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0432\u043e\u0435\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0438\u0433\u0440\u044b.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h3>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0433\u0440<\/h3>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0433\u0440 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u0440\u0443\u0434\u043e\u0435\u043c\u043a\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043e\u043d \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u0437\u043d\u0430\u043d\u0438\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430, \u0442\u0430\u043a \u0438 \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u0438 \u0432\u0441\u0435\u0445 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e, \u0435\u0441\u043b\u0438 \u0440\u0435\u0447\u044c \u0438\u0434\u0435\u0442 \u043e \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u0430\u0445. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0447\u0430\u0441\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0434 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439 \u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u043c\u0438. \u041f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u0430\u0447\u0430\u0442\u044c \u0437\u043d\u0430\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438, \u0433\u0435\u043e\u043c\u0435\u0442\u0440\u0438\u0438, \u0444\u0438\u0437\u0438\u043a\u0438. \u041d\u0430\u0432\u044b\u043a\u0438 \u0445\u0443\u0434\u043e\u0436\u043d\u0438\u043a\u0430, \u043f\u0443\u0441\u0442\u044c \u0438 \u0432 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u0431\u044a\u0435\u043c\u0435, \u0442\u043e\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0447\u0435\u043d\u044c \u043a\u0441\u0442\u0430\u0442\u0438. \u0410 \u0435\u0441\u043b\u0438 \u0438\u0433\u0440\u0430 \u0438\u043c\u0435\u0435\u0442 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u0443\u044e \u0446\u0435\u043b\u044c &#8212; \u0442\u043e \u0438 \u043c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433, \u0430\u043d\u0430\u043b\u0438\u0437 \u0440\u044b\u043d\u043a\u0430 \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f. \u0412 \u0438\u0442\u043e\u0433\u0435, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0433\u0440 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u043a\u0430\u0447\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0430\u0432\u044b\u043a\u0438 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e, \u0447\u0442\u043e \u043b\u044e\u0431\u043e\u0435 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430 \u0432 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u043e\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u043d\u0430\u0434 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0432\u0435\u0431 &#8212; \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043b\u0435\u0433\u043a\u043e\u0439 \u043f\u0440\u043e\u0433\u0443\u043b\u043a\u043e\u0439. \u0422\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u0441 \u0438\u0433\u0440\u043e\u0439 \u0432 \u043f\u043e\u0440\u0442\u0444\u043e\u043b\u0438\u043e \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0440\u0435\u0434\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u043e\u0432 \u043d\u0430 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438. \u0411\u044b\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c \u0438\u0433\u0440 &#8212; \u0432\u0435\u0441\u0435\u043b\u043e \u0438 \u043a\u0440\u0443\u0442\u043e.<\/p>\n<h3>\u0421 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c?<\/h3>\n<figure class=\"full-width\"><\/figure>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u0430\u044f \u0438\u0433\u0440\u0430 &#8212; \u0434\u043e\u0441\u0442\u043e\u0439\u043d\u0430\u044f \u0438\u0434\u0435\u044f, \u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u0432 \u043d\u043e\u0433\u0443 \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0438 \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044c \u0441\u0432\u044f\u0437\u043a\u0443:<\/p>\n<ul>\n<li>\n<p>Typescript<\/p>\n<\/li>\n<li>\n<p>React<\/p>\n<\/li>\n<li>\n<p>Webpack<\/p>\n<\/li>\n<li>\n<p>HTML\/CSS<\/p>\n<\/li>\n<li>\n<p>Phaser3<\/p>\n<\/li>\n<\/ul>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043f\u043e\u043c\u0438\u043c\u043e \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043d\u0430\u0432\u044b\u043a\u043e\u0432 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u0424\u0438\u0437\u0438\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043d\u043e\u0439 \u0433\u0440\u0430\u0444\u0438\u043a\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0428\u043a\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432 \u0432\u043f\u043e\u043b\u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0445\u0443\u0434\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0441\u043f\u0440\u0430\u0439\u0442\u044b, \u043c\u043e\u0434\u0435\u043b\u0438 \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440 \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 warcraft 2. <strong>\u0412\u0441\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u043c\u0435\u0440\u0447\u0435\u0441\u043a\u0438\u0445 \u0446\u0435\u043b\u044f\u0445.<\/strong><\/p>\n<figure class=\"\">\n<div><figcaption>\u041a\u0430\u0434\u0440 \u0438\u0437 \u0438\u0433\u0440\u044b warcraft 2<\/figcaption><\/div>\n<\/figure>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 Phaser3?<\/h2>\n<figure class=\"full-width\"><\/figure>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u044d\u0442\u043e \u0441\u0430\u043c\u044b\u0439 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0449\u0438\u0439\u0441\u044f open-source \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0445 \u0438\u0433\u0440 \u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 JavaScript\/TypeScript<\/p>\n<h3>\u041a\u0430\u043a\u0438\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u0430\u0448\u0438 \u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0430?<\/h3>\n<figure class=\"full-width\"><\/figure>\n<p><a href=\"https:\/\/phaser.io\/?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/phaser.io<\/a><\/p>\n<p><a href=\"https:\/\/labs.phaser.io\/?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/labs.phaser.io<\/a><\/p>\n<p>\u041d\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445 Phaser \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0431\u0435\u0441\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u043e\u0434\u0430, \u0438\u0433\u0440 \u0438 best-\u043f\u0440\u0430\u043a\u0442\u0438\u043a. \u0422\u0430\u043a\u0436\u0435 \u0441\u0440\u0435\u0434\u0438 \u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432: \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u043d\u043e\u0432\u044b\u0435 \u0444\u0438\u0447\u0438, \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043c\u044c\u044e\u043d\u0438\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043e\u0442\u043a\u0440\u044b\u0442\u0430\u044f \u0438 \u043f\u043e\u043b\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043a\u043d\u0438\u0433\u0438 \u043e\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044f \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 Richard Davey <strong><a class=\"mention\" href=\"\/users\/photonstorm\">@photonstorm<\/a><\/strong><\/p>\n<h3>\u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0430<\/h3>\n<p><a href=\"https:\/\/github.com\/tfkfan\/phaser3-game-demo?ref=vc.ru\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/tfkfan\/phaser3-game-demo<\/a><\/p>\n<p>\u0412\u044b\u0448\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0434\u0435\u043c\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. <\/p>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0435\u043c\u043e \u043b\u0435\u0436\u0438\u0442 \u0441\u0442\u0430\u0440\u0442\u0435\u0440 <a href=\"https:\/\/github.com\/tfkfan\/phaser3-react-template\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/tfkfan\/phaser3-react-template<\/a><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<\/p>\n<p><strong>\u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f: NodeJS >= v20, NPM >= v10<\/strong><\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c:<\/p>\n<pre><code>npm install npm start<\/code><\/pre>\n<p>\u0414\u0435\u043c\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 2 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435, \u043d\u043e \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043b\u0430\u0434\u044f\u0449\u0438\u0435 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c, \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 &#8212; React \u0438 Phaser. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c, \u0432 <em>Index.html <\/em>\u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043e \u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0432\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e:<\/p>\n<pre><code class=\"javascript\">&lt;div id=\"root\" class=\"app-container\"> ....  &lt;div id=\"game-root\"><\/code><\/pre>\n<p>\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0447\u0442\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 React \u0441 id =&#187;root&#187; \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u043c, \u043d\u0430 \u043d\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u0432\u0441\u0435 UI \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0431\u043b\u043e\u043a \u0441 z-index \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u043e\u0442 \u043d\u0443\u043b\u044f(\u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 UI \u043f\u043e\u0432\u0435\u0440\u0445 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d), \u043d\u0435\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0432 \u0432\u0435\u0440\u0441\u0442\u043a\u0435. \u0412 \u0431\u043b\u043e\u043a\u0435 id=&#187;game-root&#187; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e canvas, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u043f\u0440\u0438\u043b\u0435\u043f\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u043a \u0432\u0435\u0440\u043d\u0435\u043c\u0443 \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c.<\/p>\n<p>\u041b\u044e\u0431\u0430\u044f Phaser \u0438\u0433\u0440\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p>\n<p><em>phaser-game.ts <\/em>:<\/p>\n<pre><code class=\"javascript\">const config = {   type: Phaser.WEBGL, \/\/ \u0422\u0438\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f - WEBGL\/CANVAS   parent: 'game-root',   canvas: document.getElementById('game-canvas') as HTMLCanvasElement,   width: window.innerWidth ,   height: window.innerHeight,   pixelArt: true,   scene: [BootstrapScene, GameScene],   physics: {  \/\/ \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0434\u0432\u0438\u0436\u043a\u0430     default: 'arcade',     arcade: {       debug: false     }   } }<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0432\u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435, \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b, \u043d\u043e \u0441\u0430\u043c\u044b\u0439 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u044d\u0442\u043e \u043d\u0430\u0431\u043e\u0440 \u0441\u0446\u0435\u043d:<\/p>\n<p><strong>scene: [BootstrapScene, GameScene]<\/strong><\/p>\n<p>\u0421\u0446\u0435\u043d\u044b &#8212; \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0438\u0433\u0440\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e, \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u0432\u0441\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0432 \u0438\u0433\u0440\u0435. \u041f\u0435\u0440\u0432\u0430\u044f \u0438\u0437 \u043d\u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u0430. \u0412\u0441\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0435 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0446\u0435\u043d\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 \u0434\u0440\u0443\u0433\u0438\u0445. \u0420\u0435\u0441\u0443\u0440\u0441\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435, \u044d\u0442\u043e \u0438 \u0441\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442\u044b, \u0438 \u0430\u0442\u043b\u0430\u0441\u044b \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439, \u0438 \u0437\u0432\u0443\u043a\u043e\u0432\u044b\u0435 \u0444\u0430\u0439\u043b\u044b, Tilemap-\u0444\u0430\u0439\u043b\u044b, \u0448\u0435\u0439\u0434\u0435\u0440\u044b \u0438 \u043f\u0440.<\/p>\n<p>\u041b\u044e\u0431\u0430\u044f \u0441\u0446\u0435\u043d\u0430 \u0438\u043c\u0435\u0435\u0442 4 \u0432\u0430\u0436\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0438\u0437\u043c\u0435\u043d\u044f\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u043c\u043e\u0436\u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439:<\/p>\n<ul>\n<li>\n<p><strong><em>preload<\/em><\/strong> &#8212; \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0438 \u044d\u0442\u043e \u0432\u0441\u0435.<\/p>\n<\/li>\n<li>\n<p><strong><em>init<\/em><\/strong> &#8212; \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u043e\u043c. \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0446\u0435\u043d\u044b, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0438\u0433\u0440\u043e\u0432\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<\/li>\n<li>\n<p><strong><em>create<\/em><\/strong> &#8212; \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u0442\u044c \u0438\u0445 \u043a \u0441\u0446\u0435\u043d\u0435.<br \/> \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0432 \u044d\u0442\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435.<br \/> \u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043e\u043d\u0438 \u0441\u0430\u043c\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u0446\u0438\u043a\u043b\u0435.<\/p>\n<\/li>\n<li>\n<p><strong><em>update<\/em><\/strong> &#8212; \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0446\u0438\u043a\u043b. \u0417\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u043a\u043e\u0433\u0434\u0430 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 <strong>create<\/strong> \u0443\u0436\u0435 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447 \u044d\u0442\u043e\u0439 \u0441\u0446\u0435\u043d\u044b.<\/p>\n<pre><code class=\"javascript\">export default class BootstrapScene extends Phaser.Scene {     constructor() {         super('bootstrap')     }      init() {         store.dispatch(setLoading(true))     }      preload() {         this.load.on(Phaser.Loader.Events.PROGRESS, (value: number) => {             CONTROLS.setProgress(100 * value);         });         this.load.tilemapTiledJSON('worldmap', '.\/assets\/maps\/new\/map01merged.json');         this.load.image('tiles', '.\/assets\/maps\/new\/tiles.png');         this.load.atlas('mage', '.\/assets\/playersheets\/mage.png', '.\/assets\/playersheets\/mage.json');         this.load.image('fireball', '.\/assets\/skillsheets\/fire_002.png');         this.load.spritesheet('buff', '.\/assets\/skillsheets\/cast_001.png', {frameWidth: 192, frameHeight: 192});         this.load.image('face', '.\/assets\/images\/face.png');         this.load.spritesheet('fireballBlast', '.\/assets\/skillsheets\/s001.png', {frameWidth: 192, frameHeight: 192});         this.load.audio('intro', ['.\/assets\/music\/phaser-quest-intro.ogg']);         this.load.glsl('fireball_shader', '.\/assets\/shaders\/fireball_shader.frag');     }      create() {         CONTROLS.setProgress(100);         store.dispatch(setLoading(false))          this.sound.add('intro').play({             seek: 2.550         });          this.add.shader('fireball_shader', window.innerWidth\/2, window.innerHeight\/2, window.innerWidth ,window.innerHeight);     } }<\/code><\/pre>\n<p>\u0421\u0446\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u0432\u044b\u0432\u043e\u0434\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f React \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 <em>CONTROLS, <\/em>\u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0434\u043d\u0435\u0435<em>. <\/em>\u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u044f \u043c\u0443\u0437\u044b\u043a\u0438 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435:<\/p>\n<pre><code class=\"javascript\">this.sound.add('intro').play({             seek: 2.550 });<\/code><\/pre>\n<figure class=\"full-width\">\n<div><figcaption>\u0412\u0445\u043e\u0434\u043d\u0430\u044f \u043f\u0440\u0435\u0434\u0437\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430. \u041d\u0430 \u0437\u0430\u0434\u043d\u0435\u043c \u043f\u043b\u0430\u043d\u0435 &#8212; \u0448\u0435\u0439\u0434\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0446\u0435\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u0432\u0435\u0441\u044c \u0433\u0435\u0439\u043c\u043f\u043b\u0435\u0439 &#8212; <strong><em>GameScene.<\/em><\/strong><\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <strong><em>create:<\/em><\/strong><\/p>\n<pre><code class=\"javascript\">create() {         CONTROLS.setVersion(`Phaser v${Phaser.VERSION}`)         this.input.keyboard.on(Phaser.Input.Keyboard.Events.ANY_KEY_DOWN, (evt: { key: string; }) => {             this.player.setSkillIndex(this.skillIndexMap[evt.key])             const direction = this.keymap[evt.key]             if (direction)                 this.player.walk(direction, true)         });         this.input.keyboard.on(Phaser.Input.Keyboard.Events.ANY_KEY_UP, (evt: { key: string; }) => {             const direction = this.keymap[evt.key]             if (direction)                 this.player.walk(direction, false)         });          this.input.on(Phaser.Input.Events.POINTER_DOWN, (evt: {             worldX: number;             worldY: number;         }) => this.player.attack(new Vector2(evt.worldX, evt.worldY)));          this.createAnimations()         this.displayMap()         this.createPlayer()         this.cameras.main.startFollow(this.player)          \/\/ examples          \/\/ Animation\/Sprite         this.anims.create({             key: 'explosion',             frames: this.anims.generateFrameNumbers('fireballBlast', {start: 0, end: 19, first: 0}),             frameRate: 20,             repeat: -1         })          this.add.sprite(2500, 1100, \"\").play('explosion')          \/\/ Arcade Physics \/ collision          const items = this.add.group([this.createItem()])         this.physics.add.collider(this.player, items, (object1: Phaser.Tilemaps.Tile | Phaser.GameObjects.GameObject, object2: Phaser.Tilemaps.Tile | Phaser.GameObjects.GameObject) => {             object2.destroy(true)             setTimeout(() => {                 items.add(this.createItem(), true)             }, 3000)         })    }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439, \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0438 \u043c\u043d\u043e\u0433\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0441\u043f\u0440\u0430\u0439\u0442\u044b.<\/p>\n<p>\u0421\u043f\u0440\u0430\u0439\u0442 &#8212; \u044d\u0442\u043e \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u043d\u044b\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 &#171;\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440&#187; \u0442\u0435\u043a\u0441\u0442\u0443\u0440 \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438: \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435, \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438, \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u0438 \u0434\u0440. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"javascript\">export default class Face extends Phaser.Physics.Arcade.Sprite {     constructor(scene: Scene, x: number, y: number) {         \/\/ \u0421\u0446\u0435\u043d\u0430, \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b, \u043a\u043b\u044e\u0447 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b         super(scene, x, y, 'face');         \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a \u0444\u0438\u0437\u0438\u043a\u0435         this.scene.physics.add.existing(this)         \/\/ \u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043a \u0441\u0446\u0435\u043d\u0435         this.scene.add.existing(this)     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0442\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u0430\u0434\u0440\u043e\u0432 \u0438 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0435\u0435 \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0421\u043f\u0440\u0430\u0439\u0442-\u043b\u0438\u0441\u0442<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0432\u0437\u0440\u044b\u0432\u0430 \u0438\u0437 20 \u043d\u0430\u0440\u0435\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0432\u0435\u0440\u0445\u0443-\u0432\u043d\u0438\u0437, \u0441\u043b\u0435\u0432\u0430-\u043d\u0430\u043f\u0440\u0430\u0432\u043e \u043a\u0430\u0434\u0440\u043e\u0432 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b <em>fireballBlast<\/em>:<\/p>\n<pre><code class=\"javascript\">this.anims.create({             key: 'explosion',             frames: this.anims.generateFrameNumbers('fireballBlast', {start: 0, end: 19, first: 0}),             frameRate: 20,             repeat: -1 })<\/code><\/pre>\n<p>\u0428\u0438\u0440\u0438\u043d\u0430 \u0438 \u0432\u044b\u0441\u043e\u0442\u0430 \u043a\u0430\u0434\u0440\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043b\u044e\u0447 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0438\u0437 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0446\u0435\u043d\u0435:<\/p>\n<pre><code class=\"javascript\">this.load.spritesheet('fireballBlast', '.\/assets\/skillsheets\/s001.png', {frameWidth: 192, frameHeight: 192});<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043f\u0440\u0430\u0439\u0442 \u0432 \u0442\u043e\u0447\u043a\u0435<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\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-359210","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/359210","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=359210"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/359210\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=359210"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=359210"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=359210"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}