{"id":499667,"date":"2026-10-21T19:39:40","date_gmt":"2026-10-21T16:39:40","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=499667"},"modified":"2026-10-21T19:39:40","modified_gmt":"2026-10-21T16:39:40","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=499667","title":{"rendered":"\u041a\u0430\u043a \u044f \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u043b ESP8266 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c 3D, \u0441\u0442\u0440\u0435\u043b\u044f\u0442\u044c \u0438 \u043b\u0435\u0442\u0430\u0442\u044c: \u043f\u043e\u043b\u043d\u044b\u0439 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u043a\u043e\u0434\u0430"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!<\/p>\n<p>\u0412 <a href=\"https:\/\/habr.com\/ru\/articles\/1090534\/\" rel=\"noopener nofollow\">\u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438<\/a> \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b \u043f\u0440\u043e \u0436\u0435\u043b\u0435\u0437\u043e, \u0441\u0431\u043e\u0440\u043a\u0443 \u043a\u043e\u0440\u043f\u0443\u0441\u0430 \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u043b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0437\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0443, \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e\u0434 \u0441\u043b\u0430\u0431\u043e\u0435 \u0436\u0435\u043b\u0435\u0437\u043e.<\/p>\n<p>\u041a\u043e\u0434 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 C++ \u0432 Arduino IDE, \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0436\u0438\u0432\u0435\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435. \u0423 \u043d\u0430\u0441 \u0443\u0436\u0435 \u043f\u044f\u0442\u044c \u0438\u0433\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043e\u043c \u0447\u0435\u0440\u0435\u0437 <code>gameState<\/code>.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/09\/59\/f1\/0959f1873406bf3815ce06c5d29dff4a.jpg\" width=\"1024\" height=\"768\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/09\/59\/f1\/0959f1873406bf3815ce06c5d29dff4a.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/09\/59\/f1\/0959f1873406bf3815ce06c5d29dff4a.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p><strong>\u0411\u043b\u043e\u043a 1: Raycast \u2014 3D \u043d\u0430 \u043a\u043e\u043b\u0435\u043d\u043a\u0435<\/strong><\/p>\n<p>\u0421\u0435\u0440\u0434\u0446\u0435 \u0434\u0432\u0438\u0436\u043a\u0430 \u2014 DDA-\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c (Digital Differential Analyzer). \u041c\u044b \u043d\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043c 3D-\u043f\u043e\u043b\u0438\u0433\u043e\u043d\u044b, \u043c\u044b \u043f\u0443\u0441\u043a\u0430\u0435\u043c 320 \u043b\u0443\u0447\u0435\u0439 \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 \u0438\u0433\u0440\u043e\u043a\u0430 \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0433\u0434\u0435 \u043e\u043d\u0438 \u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430\u044e\u0442 \u0441\u0435\u0442\u043a\u0443 32&#215;32.<\/p>\n<p>\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044b<\/p>\n<pre><code>uint8_t worldMap[1024]; \/\/ 32x32<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper\"><\/span><\/a><\/div><\/pre>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>uint8_t<\/code> (1 \u0431\u0430\u0439\u0442), \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u044f \u043a\u0430\u0440\u0442\u0430 \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u0430 \u0440\u043e\u0432\u043d\u043e 1 \u041a\u0411 RAM.<\/p>\n<p>\u0418\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f \u0438\u0434\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 <code>y * 32 + x<\/code>. \u041d\u043e\u043b\u044c \u2014 \u043f\u0443\u0441\u0442\u0430\u044f \u043a\u043b\u0435\u0442\u043a\u0430, \u0435\u0434\u0438\u043d\u0438\u0446\u0430 \u2014 \u0441\u0442\u0435\u043d\u0430, \u0434\u0432\u043e\u0439\u043a\u0430 \u2014 \u0431\u0430\u0437\u0430, \u0442\u0440\u043e\u0439\u043a\u0430 \u2014 \u043a\u0443\u0431\u0438\u043a.<\/p>\n<pre><code>for(int x=0; x&lt;320; x+=2){<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>ESP8266 \u043d\u0435 \u0443\u0441\u043f\u0435\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u043e SPI 320 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043b\u0438\u043d\u0438\u0439 \u0437\u0430 \u043a\u0430\u0434\u0440.<\/p>\n<p>\u0420\u0438\u0441\u0443\u044f 160 \u043b\u0438\u043d\u0438\u0439 \u0438 \u0440\u0430\u0441\u0442\u044f\u0433\u0438\u0432\u0430\u044f \u0438\u0445 \u043d\u0430 \u0434\u0432\u0430 \u043f\u0438\u043a\u0441\u0435\u043b\u044f (<code>drawFastVLine(x, ...)<\/code> \u0438 <code>drawFastVLine(x+1, ...)<\/code>), \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0432\u0443\u043a\u0440\u0430\u0442\u043d\u044b\u0439 \u043f\u0440\u0438\u0440\u043e\u0441\u0442 FPS. \u041d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 2.4 \u0434\u044e\u0439\u043c\u0430 \u043f\u043e\u0442\u0435\u0440\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430 \u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439 \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u0430 \u0433\u043b\u0430\u0437\u0443.<\/p>\n<p> <strong>\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430 \u043b\u0443\u0447\u0430 (DDA) <\/strong> <\/p>\n<pre><code>float camX = 2.0*x\/320.0-1.0; \/\/ \u041e\u0442 -1 \u0434\u043e 1 (\u043e\u0442 \u043b\u0435\u0432\u043e\u0433\u043e \u043a\u0440\u0430\u044f \u0434\u043e \u043f\u0440\u0430\u0432\u043e\u0433\u043e)float rDX = dirX+planeX*camX, rDY = dirY+planeY*camX;float dDX = abs(1.0\/rDX), dDY = abs(1.0\/rDY); \/\/ \u0414\u043b\u0438\u043d\u0430 \u0448\u0430\u0433\u0430 \u043f\u043e \u0441\u0435\u0442\u043a\u0435<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 <code>dDX<\/code> \u0438 <code>dDY<\/code> \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u043a\u0430\u043a\u043e\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u043e \u043b\u0443\u0447\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u044c \u043e\u0434\u043d\u0443 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043b\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u043b\u0438\u043d\u0438\u044e \u0441\u0435\u0442\u043a\u0438.<\/p>\n<p>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0448\u0430\u0433\u0430\u0435\u0442 \u0432 \u0446\u0438\u043a\u043b\u0435 <code>while(!hit)<\/code>, \u0432\u044b\u0431\u0438\u0440\u0430\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043a\u0440\u0430\u0442\u0447\u0430\u0439\u0448\u0438\u0439 \u043f\u0443\u0442\u044c (\u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043b\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0439). \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e <code>worldMap<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>&gt;0<\/code> \u2014 \u043c\u044b \u043f\u043e\u043f\u0430\u043b\u0438 \u0432 \u0441\u0442\u0435\u043d\u0443.<\/p>\n<p><strong>\u042d\u0444\u0444\u0435\u043a\u0442 \u0440\u044b\u0431\u044c\u0435\u0433\u043e \u0433\u043b\u0430\u0437\u0430<\/strong><\/p>\n<pre><code>float pdist = (side == 0) ? (sDX - dDX) : (sDY - dDY);int lh = (int)(240 \/ pdist);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0441\u0442\u0435\u043d\u044b \u0432 \u0446\u0435\u043d\u0442\u0440\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u0431\u0443\u0434\u0443\u0442 \u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0432\u044b\u043f\u0443\u043a\u043b\u044b\u043c\u0438.<\/p>\n<p>\u0424\u043e\u0440\u043c\u0443\u043b\u0430 <code>(sDX - dDX)<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u043f\u0435\u043d\u0434\u0438\u043a\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \u0441\u0442\u0435\u043d\u044b, \u0443\u0431\u0438\u0440\u0430\u044f \u0438\u0441\u043a\u0430\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p><strong>\u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0441\u0442\u0435\u043d<\/strong><\/p>\n<pre><code>float wallX = (side == 0) ? (posY + pdist * rDY) : (posX + pdist * rDX);wallX -= floor(wallX); if (wallX &lt; 0.05f || wallX &gt; 0.95f) bC = 0x5AEB; else bC = (side==1?0x7BEF:0xFFFF);               <\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0442\u043e\u0447\u043a\u0443 \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u044f \u0432 \u0441\u0442\u0435\u043d\u0443, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c (<code>wallX<\/code> \u043e\u0442 0.0 \u0434\u043e 1.0).<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043b\u0443\u0447 \u043f\u043e\u043f\u0430\u043b \u0432 \u043a\u043b\u0435\u0442\u043a\u0443 \u0443 \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u0440\u0430\u044f, \u0440\u0438\u0441\u0443\u0435\u043c \u0442\u0435\u043c\u043d\u044b\u0439 \u0448\u043e\u0432. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0438\u043b\u043b\u044e\u0437\u0438\u044e \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u043d\u044b\u0445 \u0441\u043f\u0440\u0430\u0439\u0442\u043e\u0432, \u044d\u043a\u043e\u043d\u043e\u043c\u044f \u043f\u0430\u043c\u044f\u0442\u044c.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/5b\/e4\/7d\/5be47dfd5b9757bf87d99224366825a9.jpg\" width=\"682\" height=\"512\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/5b\/e4\/7d\/5be47dfd5b9757bf87d99224366825a9.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/5b\/e4\/7d\/5be47dfd5b9757bf87d99224366825a9.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p><strong>\u042d\u0444\u0444\u0435\u043a\u0442 \u0444\u043e\u043d\u0430\u0440\u044f (RGB565)<\/strong><\/p>\n<pre><code>uint16_t applyLantern(uint16_t color, float dist) {  uint8_t r = (color &gt;&gt; 11) &amp; 0x1F;  uint8_t g = (color &gt;&gt; 5) &amp; 0x3F;  uint8_t b = color &amp; 0x1F;  float factor = 1.0 - (dist \/ 12.0);  return tft.color565(r * factor * 8, g * factor * 4, b * factor * 8);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0414\u0438\u0441\u043f\u043b\u0435\u0439 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 16-\u0431\u0438\u0442\u043d\u044b\u0439 \u0446\u0432\u0435\u0442.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u0442\u0443\u0445\u0430\u043d\u0438\u0435, \u043c\u044b \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0446\u0432\u0435\u0442 \u043d\u0430 R, G, B \u043f\u043e\u0431\u0438\u0442\u043e\u0432\u044b\u043c\u0438 \u0441\u0434\u0432\u0438\u0433\u0430\u043c\u0438, \u0443\u043c\u043d\u043e\u0436\u0430\u0435\u043c \u043d\u0430 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043c\u043d\u043e\u0436\u0438\u043b\u0430 \u0431\u044b 16-\u0431\u0438\u0442\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e, \u0438 \u0446\u0432\u0435\u0442\u0430 \u0431\u044b \u00ab\u043f\u043e\u043f\u043b\u044b\u043b\u0438\u00bb.<\/p>\n<p><strong>\u0417\u0432\u0435\u0437\u0434\u044b \u0438 HUD<\/strong><\/p>\n<pre><code>if (starY[i] &lt; topWall[starX[i]]) tft.drawPixel(starX[i], starY[i], TFT_WHITE);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u0437\u0432\u0435\u0437\u0434\u044b \u043d\u0435 \u043f\u0440\u043e\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u043b\u0438 \u0441\u043a\u0432\u043e\u0437\u044c \u0441\u0442\u0435\u043d\u044b, \u043c\u044b \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0441\u0442\u0435\u043d \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c \u0432\u044b\u0441\u043e\u0442\u0443 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0442\u043e\u0447\u043a\u0438 \u0441\u0442\u0435\u043d\u044b \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 <code>topWall[x]<\/code>.<\/p>\n<p>\u041f\u0440\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0435 \u0437\u0432\u0435\u0437\u0434\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0438\u0436\u0435 \u043b\u0438 \u043e\u043d\u0430 \u0441\u0442\u0435\u043d\u044b. \u0415\u0441\u043b\u0438 \u0434\u0430 \u2014 \u043d\u0435 \u0440\u0438\u0441\u0443\u0435\u043c. HUD (<code>Lvl:... Items:...<\/code>) \u0432\u044b\u043d\u0435\u0441\u0435\u043d \u0432 \u0441\u0430\u043c\u044b\u0439 \u043a\u043e\u043d\u0435\u0446, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u043b\u0438 \u0441\u0442\u0435\u043d\u044b.<\/p>\n<p><strong>\u041a\u043e\u043b\u043b\u0438\u0437\u0438\u0438 \u0438 \u0431\u0430\u0433 \u00ab\u0437\u0430\u0441\u0442\u0440\u0435\u0432\u0430\u043d\u0438\u044f\u00bb<\/strong><\/p>\n<pre><code>int nextX = (int)(posX + dirX*0.3);if(worldMap[(int)posY*32 + nextX] != 1 &amp;&amp; worldMap[(int)posY*32 + nextX] != 2) posX += dirX*ms;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 (\u0438 \u044f \u043d\u0430 \u044d\u0442\u0438 \u0436\u0435 \u0433\u0440\u0430\u0431\u043b\u0438 \u043d\u0430\u0441\u0442\u0443\u043f\u0438\u043b, \u0447\u0435\u0433\u043e \u0433\u0440\u0435\u0445\u0430 \u0442\u0430\u0438\u0442\u044c..) \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u044e \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043a\u043b\u0435\u0442\u043a\u0435. \u0415\u0441\u043b\u0438 \u0438\u0433\u0440\u043e\u043a \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0432 \u0441\u0442\u0435\u043d\u0435, \u043e\u043d \u0437\u0430\u0441\u0442\u0440\u0435\u0432\u0430\u0435\u0442 \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430.<\/p>\n<p>\u041c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043b\u0435\u0442\u043a\u0443 (<code>nextX<\/code>, <code>nextY<\/code>), \u0440\u0430\u0437\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e \u043e\u0441\u044f\u043c X \u0438 Y. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u00ab\u0441\u043a\u043e\u043b\u044c\u0437\u0438\u0442\u044c\u00bb \u0432\u0434\u043e\u043b\u044c \u0441\u0442\u0435\u043d.<\/p>\n<h2> \u0411\u043b\u043e\u043a 2: Space Invaders \u2014 \u0411\u043e\u0441\u0441\u044b \u0438 \u0431\u043e\u043d\u0443\u0441\u044b  <\/h2>\n<p> <strong>\u0414\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0437\u0438\u0433\u0437\u0430\u0433\u043e\u043c<\/strong>  <\/p>\n<pre><code>if (millis() - lastAlienMove &gt; 500) {  alienX += (10 * alienDir);   if (alienX &gt; 180 || alienX &lt; 5) { alienDir *= -1; alienY += 10; }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u0440\u0438\u0448\u0435\u043b\u044c\u0446\u044b \u0434\u0432\u0438\u0433\u0430\u044e\u0442\u0441\u044f \u0433\u0440\u0443\u043f\u043f\u043e\u0439. \u041a\u043e\u0433\u0434\u0430 \u0433\u0440\u0443\u043f\u043f\u0430 \u0443\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u0440\u0430\u0439 \u044d\u043a\u0440\u0430\u043d\u0430, \u043c\u044b \u043c\u0435\u043d\u044f\u0435\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0435\u0435 \u0432\u043d\u0438\u0437 \u043d\u0430 10 \u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439.<\/p>\n<p><strong>\u0411\u043e\u043d\u0443\u0441\u044b \u0438 \u0430\u043d\u0442\u0438\u0431\u043e\u043d\u0443\u0441\u044b<\/strong><\/p>\n<pre><code>if (!bonusActive &amp;&amp; random(5) == 1) {   bonusActive = true;   bonusType = random(1, 4); }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0421 \u0448\u0430\u043d\u0441\u043e\u043c 20% (1 \u043a 5) \u0438\u0437 \u0441\u0431\u0438\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0448\u0435\u043b\u044c\u0446\u0430 \u0432\u044b\u043f\u0430\u0434\u0430\u0435\u0442 \u0431\u043e\u043d\u0443\u0441.<\/p>\n<p>\u0422\u0438\u043f\u044b \u0431\u043e\u043d\u0443\u0441\u043e\u0432:<\/p>\n<ul>\n<li>\n<p><strong>\u0416\u0438\u0437\u043d\u044c:<\/strong> \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0436\u0438\u0437\u043d\u044c (<code>lives++<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435:<\/strong> \u0423\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 (<code>rapidFireTimer = millis()+5000<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u043d\u0442\u0438\u0431\u043e\u043d\u0443\u0441:<\/strong> \u0423\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0432\u0440\u0430\u0433\u043e\u0432 (<code>enemyRapidFireTimer = millis()+5000<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0411\u043e\u0441\u0441 \u0438 \u0441\u0438\u043d\u0443\u0441\u043e\u0438\u0434\u0430<\/strong><\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/85\/26\/66\/852666cd7b08781ec3b69da5b1aa7d9f.jpg\" width=\"1024\" height=\"768\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/85\/26\/66\/852666cd7b08781ec3b69da5b1aa7d9f.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/85\/26\/66\/852666cd7b08781ec3b69da5b1aa7d9f.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<pre><code>int wave = sin(millis()*0.005)*10;tft.fillTriangle(bossX+5, bossY+20, bossX+8, bossY+20, bossX+5+wave, bossY+35, TFT_RED);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0440\u0435\u0442\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u2014 \u0431\u043e\u0441\u0441. \u0415\u0433\u043e \u0449\u0443\u043f\u0430\u043b\u044c\u0446\u0430 (\u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0438) \u043a\u0430\u0447\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0441\u0438\u043d\u0443\u0441\u043e\u0438\u0434\u0435 \u043e\u0442 <code>millis()<\/code>. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442 \u0436\u0438\u0432\u043e\u0433\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043c\u0430 \u0431\u0435\u0437 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0441\u043f\u0440\u0430\u0439\u0442\u043e\u0432.<\/p>\n<p>\u041f\u0440\u0438 \u0441\u043c\u0435\u0440\u0442\u0438 \u0431\u043e\u0441\u0441\u0430 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0446\u0438\u043a\u043b \u0438\u0437 15 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439:<\/p>\n<pre><code>tft.fillCircle(rx, ry, random(5, 15), TFT_WHITE);tone(BUZZER_PIN, (unsigned int)random(100, 800), 40);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442 \u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043a\u0440\u0443\u0433\u043e\u0432 \u0438 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u0437\u0432\u0443\u043a\u043e\u0432 \u2014 \u043a\u043b\u0430\u0441\u0441\u0438\u043a\u0430 \u0441\u0442\u0430\u0440\u044b\u0445 \u0430\u0440\u043a\u0430\u0434.<\/p>\n<h2> \u0411\u043b\u043e\u043a 3: Space Junker (Asteroids) \u2014 \u0418\u043d\u0435\u0440\u0446\u0438\u044f \u0438 \u0444\u0438\u0437\u0438\u043a\u0430  <\/h2>\n<p> <strong>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445<\/strong>  <\/p>\n<pre><code>struct Asteroid { float x, y; float speedX, speedY; int size; bool active; };struct Bullet { float x, y; float speedX, speedY; bool active; };<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p> \u0412\u043c\u0435\u0441\u0442\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432 <code>float asteroidX[10]<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b. \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u043e\u0434 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c, \u0430 \u043f\u0430\u043c\u044f\u0442\u044c \u0440\u0430\u0441\u0445\u043e\u0434\u0443\u0435\u0442\u0441\u044f \u0442\u0430\u043a \u0436\u0435.  <\/p>\n<p> <strong>\u0418\u043d\u0435\u0440\u0446\u0438\u044f \u0432 \u0432\u0430\u043a\u0443\u0443\u043c\u0435<\/strong>  <\/p>\n<pre><code>if (digitalRead(PIN_BTN_A) == LOW) {  junkerSpeedX += cos(junkerAngle) * 0.1;  junkerSpeedY += sin(junkerAngle) * 0.1;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0412 \u043a\u043e\u0441\u043c\u043e\u0441\u0435 \u043d\u0435\u0442 \u0442\u0440\u0435\u043d\u0438\u044f. \u041d\u0430\u0436\u0430\u043b \u043d\u0430 \u0442\u044f\u0433\u0443 \u2014 \u043a\u043e\u0440\u0430\u0431\u043b\u044c \u0443\u0441\u043a\u043e\u0440\u0438\u043b\u0441\u044f. \u041e\u0442\u043f\u0443\u0441\u0442\u0438\u043b \u2014 \u043b\u0435\u0442\u0438\u0442 \u043f\u043e \u0438\u043d\u0435\u0440\u0446\u0438\u0438.<\/p>\n<p>\u041c\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c (<code>if (junkerSpeedX &gt; 2) junkerSpeedX = 2;<\/code>), \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u0440\u0430\u0431\u043b\u044c \u043d\u0435 \u0443\u043b\u0435\u0442\u0430\u043b \u0437\u0430 \u043a\u0430\u0434\u0440 \u0437\u0430 \u043e\u0434\u043d\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438.<\/p>\n<p> <strong>\u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044f<\/strong>  <\/p>\n<pre><code>if (junkerX &lt; 0) junkerX = 320; if (junkerX &gt; 320) junkerX = 0;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0423\u043b\u0435\u0442\u0435\u043b \u0437\u0430 \u043f\u0440\u0430\u0432\u044b\u0439 \u043a\u0440\u0430\u0439 \u2014 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0441\u043b\u0435\u0432\u0430. \u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0433\u0440\u0435 \u0434\u0438\u043d\u0430\u043c\u0438\u043a\u0438.<\/p>\n<p><strong>\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u0442\u0440\u0435\u043b\u044c\u0431\u0430 (\u0422\u0430\u0439\u043c\u0435\u0440)<\/strong><\/p>\n<pre><code>if (digitalRead(PIN_BTN_B) == LOW) {  if (millis() - lastJunkerShot &gt; 200) {     lastJunkerShot = millis();    \/\/ ... \u0432\u044b\u043b\u0435\u0442 \u043f\u0443\u043b\u0438 ...  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043d\u0430\u0436\u0438\u043c\u0430\u0442\u044c \u0431\u0435\u0437 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 , \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0430\u0439\u043c\u0435\u0440 <code>millis()<\/code>.<\/p>\n<p>\u0417\u0430\u0436\u0430\u043b \u043a\u043d\u043e\u043f\u043a\u0443 \u2014 \u0441\u0442\u0440\u0435\u043b\u044f\u0435\u0448\u044c \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 5 \u0432\u044b\u0441\u0442\u0440\u0435\u043b\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443. <code>delay()<\/code> \u0442\u0443\u0442 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442, \u043e\u043d \u0431\u044b \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u043b \u0438\u0433\u0440\u0443.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/6b\/8d\/ac\/6b8dac4ac66612cd40dbd51db50a5606.jpg\" width=\"1024\" height=\"768\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/6b\/8d\/ac\/6b8dac4ac66612cd40dbd51db50a5606.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/6b\/8d\/ac\/6b8dac4ac66612cd40dbd51db50a5606.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p><strong>\u0414\u0440\u043e\u0431\u043b\u0435\u043d\u0438\u0435 \u0430\u0441\u0442\u0435\u0440\u043e\u0438\u0434\u043e\u0432<\/strong><\/p>\n<pre><code>if (asteroids[j].size &gt; 1) {  for (int k = 0; k &lt; 2; k++) {    asteroids[m].size = asteroids[j].size - 1;    asteroids[m].speedX = cos(angle) * (asteroids[j].size == 3 ? 1.0 : 1.5);  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u0443\u043b\u044f \u043f\u043e\u043f\u0430\u043b\u0430 \u0432 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0430\u0441\u0442\u0435\u0440\u043e\u0438\u0434? \u041e\u043d \u043d\u0435 \u0438\u0441\u0447\u0435\u0437\u0430\u0435\u0442, \u0430 \u0441\u043f\u0430\u0432\u043d\u0438\u0442 \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445, \u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 (<code>size - 1<\/code>).<\/p>\n<p>\u041e\u0441\u043a\u043e\u043b\u043a\u0438 \u043b\u0435\u0442\u044f\u0442 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0438 \u0441 \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0445\u0430\u043e\u0441 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435.<\/p>\n<p><strong>\u0411\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0441\u043f\u0430\u0432\u043d<\/strong><\/p>\n<pre><code>bool allDestroyed = true;for (int i = 0; i &lt; 10; i++) if (asteroids[i].active) allDestroyed = false;if (allDestroyed) { junkerScore += 50; \/* \u0421\u043f\u0430\u0432\u043d \u043d\u043e\u0432\u043e\u0439 \u0432\u043e\u043b\u043d\u044b *\/ }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041d\u0430 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u0438 \u0430\u0441\u0442\u0435\u0440\u0438\u0434\u043e\u0432 \u0438\u0433\u0440\u0430 \u043d\u0435 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<p>\u041c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u043b\u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u0438 \u0435\u0441\u043b\u0438 \u0438\u0445 \u043d\u0435\u0442 \u2014 \u0441\u043f\u0430\u0432\u043d\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u0432\u043e\u043b\u043d\u0443 \u0438 \u0434\u0430\u0435\u043c \u0431\u043e\u043d\u0443\u0441\u043d\u044b\u0435 \u043e\u0447\u043a\u0438.<\/p>\n<h2> \u0418\u0442\u043e\u0433  <\/h2>\n<p> \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u044d\u0439\u043a\u0430\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f 3D, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0438 \u0442\u0440\u0438\u0433\u043e\u043d\u043e\u043c\u0435\u0442\u0440\u0438\u044e \u0434\u043b\u044f \u00ab\u0410\u0441\u0442\u0435\u0440\u043e\u0438\u0434\u043e\u0432\u00bb, \u0438 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0451 \u044d\u0442\u043e \u0434\u0440\u0443\u0436\u0438\u043b\u043e \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439. \u0418 \u0434\u0430, \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u0433\u0440 \u0438 \u0438\u0445 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043f\u043e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u0438 \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0438\u0437\u043d\u0435\u0441\u0435\u043d\u043e \u043d\u0435\u043c\u0430\u043b\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043a\u043b\u0438\u043d\u0430\u043d\u0438\u0439.. \u0421\u0442\u0438\u0432 \u0437\u0430\u0441\u0442\u0440\u0435\u0432\u0430\u043b \u0432 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430\u0445, \u0441\u043f\u0430\u0432\u043d\u0438\u043b\u0441\u044f \u0432 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0442\u0435\u043d\u043e\u0439 \u0438 \u0431\u0430\u0437\u043e\u0439 \u0432 \u0441\u0430\u043c\u043e\u043c \u0443\u0433\u043b\u0443 \u0438 \u043d\u0435 \u043c\u043e\u0433 \u0432\u044b\u0439\u0442\u0438&#8230; \u0417\u0430\u0431\u043e\u0440 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u0430\u0432\u043e\u043a \u0432 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u0445 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u043a\u0443\u0431\u0438\u043a\u043e\u0432 \u043d\u0430\u0440\u0435\u0437\u0430\u043b\u0441\u044f \u043d\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b, \u043a\u0430\u043a \u0438 \u0441\u0430\u043c\u0438 \u043a\u0443\u0431\u0438\u043a\u0438&#8230; \u042d\u0442\u0438 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u044f \u043e\u043f\u0443\u0441\u0442\u0438\u043b. \u041d\u043e \u0441\u0430\u043c\u044b\u0439 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0431\u0430\u0433, \u044f \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u0431\u0435\u0434\u0438\u043b. \u0421\u0442\u0438\u0432 \u043c\u0435\u0440\u0446\u0430\u0435\u0442. \u0427\u0442\u043e \u0431\u044b \u044f \u043d\u0435 \u0434\u0435\u043b\u0430\u043b. \u0414\u0430\u0436\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0432 \u0435\u0433\u043e \u0432 HUD, \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u043a \u0441\u043b\u043e\u0432\u0443, \u0442\u043e\u0436\u0435 \u043c\u0435\u0440\u0446\u0430\u0435\u0442. \u0421\u043c\u0438\u0440\u0438\u043b\u0441\u044f \u0432 \u0438\u0442\u043e\u0433\u0435 \u0438 \u043e\u0442\u043d\u043e\u0448\u0443\u0441\u044c \u043a\u0430\u043a \u043a \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u043e\u043c\u0443 \u0437\u043b\u0443..<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/60\/06\/3f\/60063f00a801fdda266bf6ffa33e9c2e.jpg\" alt=\"\u041f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0421\u0442\u0438\u0432\u0430 \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0435 \u043f\u043e\u0434 \u0446\u0432\u0435\u0442 \u043f\u043e\u043b\u0430\" title=\"\u041f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0421\u0442\u0438\u0432\u0430 \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0435 \u043f\u043e\u0434 \u0446\u0432\u0435\u0442 \u043f\u043e\u043b\u0430\" width=\"512\" height=\"682\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/60\/06\/3f\/60063f00a801fdda266bf6ffa33e9c2e.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/60\/06\/3f\/60063f00a801fdda266bf6ffa33e9c2e.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0421\u0442\u0438\u0432\u0430 \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0435 \u043f\u043e\u0434 \u0446\u0432\u0435\u0442 \u043f\u043e\u043b\u0430<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/8c\/bf\/99\/8cbf99efebf399a1e6c77d6ab6d729dc.jpg\" alt=\"\u042d\u0442\u043e \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435 \u0431\u0430\u0437\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0421\u0442\u0438\u0432 \u043d\u043e\u0441\u0438\u0442 \u043a\u0443\u0431\u0438\u043a\u0438\" title=\"\u042d\u0442\u043e \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435 \u0431\u0430\u0437\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0421\u0442\u0438\u0432 \u043d\u043e\u0441\u0438\u0442 \u043a\u0443\u0431\u0438\u043a\u0438\" width=\"512\" height=\"682\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/8c\/bf\/99\/8cbf99efebf399a1e6c77d6ab6d729dc.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/8c\/bf\/99\/8cbf99efebf399a1e6c77d6ab6d729dc.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u043e \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435 \u0431\u0430\u0437\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0421\u0442\u0438\u0432 \u043d\u043e\u0441\u0438\u0442 \u043a\u0443\u0431\u0438\u043a\u0438<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/ea\/2f\/dd\/ea2fdddaab66a2819caeeb0470cf1ade.jpg\" alt=\"\u041f\u043e\u043f\u044b\u0442\u043a\u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a\u0438\" title=\"\u041f\u043e\u043f\u044b\u0442\u043a\u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a\u0438\" width=\"512\" height=\"682\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/ea\/2f\/dd\/ea2fdddaab66a2819caeeb0470cf1ade.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/ea\/2f\/dd\/ea2fdddaab66a2819caeeb0470cf1ade.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u043e\u043f\u044b\u0442\u043a\u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a\u0438<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u043e\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. <\/p>\n<pre><code class=\"cpp\">#include &lt;SPI.h&gt;#include &lt;TFT_eSPI.h&gt;#include &lt;EEPROM.h&gt;TFT_eSPI tft = TFT_eSPI();\/\/ --- \u041f\u0418\u041d\u042b \u0418 \u041d\u0410\u0421\u0422\u0420\u041e\u0419\u041a\u0418 ---#define PIN_JOY_X A0#define PIN_BTN_A D3 #define PIN_BTN_B D0 #define BUZZER_PIN D6#define SKIN 0xFD42#define SHIRT 0x255A#define PANTS 0x2235\/\/ \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435int gameState = 0, menuSelection = 1;bool isPaused = false, lastBtnBState = HIGH;\/\/ ==========================================================\/\/ --- \u0411\u041b\u041e\u041a 1: RAYCAST (MINECRAFT) ---\/\/ ==========================================================float posX = 2.5, posY = 2.5, dirX = 1.0, dirY = 0.0, planeX = 0.0, planeY = 0.66;bool hasItem = false; int itemsInBase = 0, totalItemsInLevel = 10, currentLevel = 1;uint8_t worldMap[1024]; int starX[40], starY[40];int topWall[320]; void generateMap() {  for(int i=0; i&lt;1024; i++) worldMap[i] = 0;  for(int i=0; i&lt;32; i++) { worldMap[i]=1; worldMap[992+i]=1; worldMap[i*32]=1; worldMap[i*32+31]=1; }  for(int i=6; i&lt;26; i++) { worldMap[16*32+i]=1; worldMap[i*32+16]=1; }    \/\/ \u0411\u0410\u0417\u0410 (2) \u0412 \u0426\u0415\u041d\u0422\u0420\u0415  worldMap[10*32+10]=2; worldMap[10*32+11]=2;   worldMap[11*32+10]=2; worldMap[11*32+11]=2;  int count = 0;   while(count &lt; totalItemsInLevel) {    int rx = random(1, 31), ry = random(1, 31);    if(worldMap[ry*32+rx] == 0) { worldMap[ry*32+rx] = 3; count++; }  }}uint16_t applyLantern(uint16_t color, float dist) {  float range = 12.0; if(dist &gt; range) return TFT_BLACK;  uint8_t r = (color &gt;&gt; 11) &amp; 0x1F, g = (color &gt;&gt; 5) &amp; 0x3F, b = color &amp; 0x1F;  float factor = 1.0 - (dist \/ range); return tft.color565(r * factor * 8, g * factor * 4, b * factor * 8);}void loopRaycast() {  int val = analogRead(PIN_JOY_X);  float rot = (val &lt; 400) ? 0.07 : (val &gt; 600 ? -0.07 : 0);  if (rot != 0) {    float odX = dirX; dirX = dirX*cos(rot)-dirY*sin(rot); dirY = odX*sin(rot)+dirY*cos(rot);    float opX = planeX; planeX = planeX*cos(rot)-planeY*sin(rot); planeY = opX*sin(rot)+planeY*cos(rot);  }    if (digitalRead(PIN_BTN_A) == LOW) {    float ms = 0.1;     int nextX = (int)(posX + dirX*0.3);    int nextY = (int)(posY + dirY*0.3);    if(worldMap[(int)posY*32 + nextX] != 1 &amp;&amp; worldMap[(int)posY*32 + nextX] != 2) posX += dirX*ms;    if(worldMap[nextY*32 + (int)posX] != 1 &amp;&amp; worldMap[nextY*32 + (int)posX] != 2) posY += dirY*ms;  }    static bool lastB = HIGH; bool curB = digitalRead(PIN_BTN_B);  if(curB == LOW &amp;&amp; lastB == HIGH) {    int mx = (int)(posX + dirX*0.6), my = (int)(posY + dirY*0.6);    int target = worldMap[my*32+mx];        if(!hasItem &amp;&amp; target == 3) {         worldMap[my*32+mx] = 0; hasItem = true; tone(BUZZER_PIN, 1200, 100);     }     else if(hasItem &amp;&amp; target == 2) {       hasItem = false; itemsInBase++; tone(BUZZER_PIN, 800, 150);      if(itemsInBase &gt;= totalItemsInLevel) { currentLevel++; totalItemsInLevel++; itemsInBase = 0; generateMap(); }    }    delay(200);  }  lastB = curB;  tft.startWrite();  for(int x=0; x&lt;320; x+=2){    float camX = 2.0*x\/320.0-1.0; float rDX = dirX+planeX*camX, rDY = dirY+planeY*camX;    int mX = (int)posX, mY = (int)posY; float dDX = abs(1.0\/rDX), dDY = abs(1.0\/rDY), sDX, sDY; int stX, stY, side;    if(rDX &lt; 0){ stX = -1; sDX = (posX-mX)*dDX; } else { stX = 1; sDX = (mX + 1.0 - posX) * dDX; }    if(rDY &lt; 0){ stY = -1; sDY = (posY - mY) * dDY; } else { stY = 1; sDY = (mY + 1.0 - posY) * dDY; }        bool hit = false;     while(!hit){       if(sDX &lt; sDY){ sDX += dDX; mX += stX; side = 0; }       else { sDY += dDY; mY += stY; side = 1; }       if(worldMap[mY*32+mX]&gt;0) hit = true;     }        float pdist = (side == 0) ? (sDX - dDX) : (sDY - dDY);     int lh = (int)(240 \/ pdist);    uint8_t cell = worldMap[mY*32+mX];        float wallX = (side == 0) ? (posY + pdist * rDY) : (posX + pdist * rDX);    wallX -= floor(wallX);     uint16_t bC;    if(cell == 1) {        if (wallX &lt; 0.05f || wallX &gt; 0.95f) bC = 0x5AEB;         else bC = (side==1?0x7BEF:0xFFFF);                    }    else if(cell == 2) bC = TFT_YELLOW;                       else bC = TFT_BLUE;                                       uint16_t finalColor = applyLantern(bC, pdist);        int ds = max(0, -lh\/2+120);     int de = min(239, lh\/2+120);     tft.drawFastVLine(x, 0, ds, 0x2104);     tft.drawFastVLine(x, de, 240-de, 0x1082);    tft.drawFastVLine(x+1, 0, ds, 0x2104);     tft.drawFastVLine(x+1, de, 240-de, 0x1082);    if (cell == 1) {        tft.drawFastVLine(x, ds, de-ds, finalColor);        tft.drawFastVLine(x+1, ds, de-ds, finalColor);    } else {        int blockH = (de - ds) \/ 2;         int blockTop = de - blockH;        tft.drawFastVLine(x, blockTop, blockH, finalColor);        tft.drawFastVLine(x+1, blockTop, blockH, finalColor);    }    topWall[x] = ds;    topWall[x+1] = ds;  }  tft.endWrite();   for(int i=0; i&lt;40; i++) {      if (starY[i] &lt; topWall[starX[i]]) {           tft.drawPixel(starX[i], starY[i], TFT_WHITE);      }  }  int bob = (digitalRead(PIN_BTN_A) == LOW) ? sin(millis()*0.01)*5 : 0;  int sx = 144, sy = 180 + bob;   tft.fillRect(sx+8, sy, 16, 16, SKIN);     tft.fillRect(sx, sy+16, 32, 24, SHIRT);   tft.fillRect(sx+4, sy+40, 24, 24, PANTS);   if(hasItem) tft.fillRect(sx+8, sy+20, 16, 16, TFT_BLUE);   tft.fillRect(0, 0, 240, 20, TFT_BLACK);   tft.setTextColor(TFT_GREEN, TFT_BLACK);   tft.setCursor(5, 5);   tft.printf(\"Lvl:%d Items:%d\/%d\", currentLevel, itemsInBase, totalItemsInLevel);   yield();}\/\/ ==========================================================\/\/ --- \u0411\u041b\u041e\u041a 2: SPACE INVADERS ---\/\/ ==========================================================int shipX = 160, lives = 4, score = 0, highScore = 0;bool aliens[15]; int alienX = 10, alienY = 30, alienDir = 1, aliensCount = 15;int bulletX, bulletY; bool bulletActive = false;int enBulletX, enBulletY; bool enBulletActive = false;int bonusX, bonusY, bonusType; bool bonusActive = false;unsigned long lastAlienMove = 0, rapidFireTimer = 0, enemyRapidFireTimer = 0, shieldTimer = 0;bool isBossLevel = false; int bossHP, bossMaxHP = 5, bossX = 140, bossY = 30, bossDir = 2, levelCounter = 1;void drawUIInvaders() {  tft.setTextColor(TFT_YELLOW, TFT_BLACK); tft.setCursor(5, 5);  tft.printf(\"SCORE:%d HI:%d LIVES:%d   \", score, highScore, lives); }void resetInvadersLevel() {  aliensCount = 15; for(int i=0; i&lt;15; i++) aliens[i] = true;  alienX = 10; alienY = 30; tft.fillScreen(TFT_BLACK); drawUIInvaders();}void bossExplosion() {  score += 100; isBossLevel = false; levelCounter++;  for (int i = 0; i &lt; 15; i++) {    int rx = bossX + random(-10, 40); int ry = bossY + random(-10, 20);    tft.fillCircle(rx, ry, random(5, 15), TFT_WHITE);    tone(BUZZER_PIN, (unsigned int)random(100, 800), 40); delay(40);    tft.fillCircle(rx, ry, 15, TFT_BLACK);  }  resetInvadersLevel();}void loopInvaders() {  bool curB = digitalRead(PIN_BTN_B);  if (curB == LOW &amp;&amp; lastBtnBState == HIGH) {     isPaused = !isPaused;     if (!isPaused) { tft.fillRect(110, 105, 100, 30, TFT_BLACK); }    delay(200);   }  lastBtnBState = curB;   if (isPaused) { tft.drawCentreString(\"PAUSE\", 160, 110, 4); return; }  int xVal = analogRead(PIN_JOY_X); int oldX = shipX;  if (xVal &lt; 400) shipX += 5; if (xVal &gt; 600) shipX -= 5;  shipX = constrain(shipX, 0, 300);  if (shipX != oldX) {     uint16_t clr = (shieldTimer &gt; millis()) ? TFT_YELLOW : TFT_GREEN;    tft.fillRect(oldX, 210, 20, 10, TFT_BLACK); tft.fillRect(shipX, 210, 20, 10, clr);   }  int pSpeed = (rapidFireTimer &gt; millis()) ? 12 : 7;  if (digitalRead(PIN_BTN_A) == LOW &amp;&amp; !bulletActive) { bulletActive=true; bulletX=shipX+10; bulletY=205; tone(BUZZER_PIN,1200,15); }  if (bulletActive) {    tft.drawFastVLine(bulletX, bulletY, 6, TFT_BLACK); bulletY -= pSpeed;    if (bulletY &lt; 10) bulletActive = false;    else {      tft.drawFastVLine(bulletX, bulletY, 6, (rapidFireTimer &gt; millis() ? TFT_CYAN : TFT_WHITE));      if (isBossLevel) { if (bulletX &gt; bossX &amp;&amp; bulletX &lt; bossX+40 &amp;&amp; bulletY &gt; bossY &amp;&amp; bulletY &lt; bossY+20) { bulletActive=false; bossHP--; if(bossHP&lt;=0) bossExplosion(); } }      else { for(int i=0; i&lt;15; i++) if(aliens[i]) { int ax=alienX+(i%5)*25, ay=alienY+(i\/5)*20; if(bulletX &gt; ax &amp;&amp; bulletX &lt; ax+20 &amp;&amp; bulletY &gt; ay &amp;&amp; bulletY &lt; ay+15)       { aliens[i]=false; bulletActive=false; aliensCount--; score+=10; tft.fillRect(ax, ay, 20, 15, TFT_BLACK); drawUIInvaders();        if (!bonusActive &amp;&amp; random(5) == 1) {           bonusActive = true; bonusX = ax + 6; bonusY = ay; bonusType = random(1, 4);         }       } } }     }  }  if (isBossLevel) {    tft.fillRect(bossX-15, bossY-12, 75, 55, TFT_BLACK); bossX += bossDir; if(bossX&gt;280 || bossX&lt;0) bossDir*=-1;    int wave = sin(millis()*0.005)*10;    tft.fillTriangle(bossX+5, bossY+20, bossX+8, bossY+20, bossX+5+wave, bossY+35, TFT_RED);    tft.fillTriangle(bossX+33, bossY+20, bossX+36, bossY+20, bossX+35+wave, bossY+35, TFT_GREEN);    tft.fillRect(bossX, bossY, 40, 20, TFT_MAGENTA);    int barW = map(bossHP, 0, bossMaxHP, 0, 60); tft.drawRect(bossX-10, bossY-10, 60, 4, TFT_WHITE); tft.fillRect(bossX-10, bossY-10, barW, 4, TFT_RED);    if(!enBulletActive &amp;&amp; random(40)==1){ enBulletActive=true; enBulletX=bossX+20-wave; enBulletY=bossY+35; }  } else {    if (millis() - lastAlienMove &gt; 500) {      for(int i=0;i&lt;15;i++) if(aliens[i]) tft.fillRect(alienX+(i%5)*25, alienY+(i\/5)*20, 20, 15, TFT_BLACK);      alienX += (10 * alienDir); if (alienX &gt; 180 || alienX &lt; 5) { alienDir *= -1; alienY += 10; }      for(int i=0;i&lt;15;i++) if(aliens[i]) tft.fillRect(alienX+(i%5)*25, alienY+(i\/5)*20, 20, 15, TFT_RED);      lastAlienMove = millis();    }    int eChance = (enemyRapidFireTimer &gt; millis()) ? 5 : 40;    if (!enBulletActive &amp;&amp; random(eChance)==1) { int s=random(15); if(aliens[s]) { enBulletActive=true; enBulletX=alienX+(s%5)*25+10; enBulletY=alienY+(s\/5)*20+15; } }  }  if (enBulletActive) {    tft.drawFastVLine(enBulletX, enBulletY, 8, TFT_BLACK); enBulletY += 5;    if (enBulletY &gt; 240) enBulletActive = false;    else { tft.drawFastVLine(enBulletX, enBulletY, 8, TFT_YELLOW); if (enBulletX &gt; shipX &amp;&amp; enBulletX &lt; shipX+20 &amp;&amp; enBulletY &gt; 210)     { enBulletActive=false; lives--; tone(BUZZER_PIN, 100, 200); drawUIInvaders(); if(lives&lt;=0) { if(score&gt;highScore) { EEPROM.put(0, score); EEPROM.commit(); } gameState=0; } } }  }  if (bonusActive) {    tft.fillRect(bonusX, bonusY, 8, 8, TFT_BLACK); bonusY += 3;    if (bonusY &gt; 240) bonusActive = false;    else { uint16_t bClr = (bonusType==1?TFT_RED : (bonusType==2?TFT_BLUE:TFT_YELLOW)); tft.fillRect(bonusX, bonusY, 8, 8, bClr);      if (bonusX &gt; shipX &amp;&amp; bonusX &lt; shipX+20 &amp;&amp; bonusY &gt; 210) { bonusActive=false; tft.fillRect(bonusX, bonusY, 8, 8, TFT_BLACK); if(bonusType==1) lives++;      if(bonusType==2) rapidFireTimer=millis()+5000; if(bonusType==3) enemyRapidFireTimer=millis()+5000; drawUIInvaders(); }    }  }  if(aliensCount &lt;= 0 &amp;&amp; !isBossLevel) { levelCounter++; if(levelCounter%3==0) { isBossLevel=true; bossHP=5; tft.fillScreen(TFT_BLACK); } else resetInvadersLevel(); }  delay(15);}\/\/ ==========================================================\/\/ --- \u0411\u041b\u041e\u041a 3: SPACE JUNKER (ASTEROIDS) ---\/\/ ==========================================================struct Asteroid { float x, y; float speedX, speedY; int size; bool active; };struct Bullet { float x, y; float speedX, speedY; bool active; };float junkerX, junkerY, junkerAngle, junkerSpeedX, junkerSpeedY;int junkerScore = 0, junkerLives = 3;Asteroid asteroids[10];Bullet bullets[5];unsigned long lastJunkerShot = 0;void resetAsteroids() {  junkerX = 160; junkerY = 120; junkerAngle = 0;  junkerSpeedX = 0; junkerSpeedY = 0; junkerScore = 0; junkerLives = 3;  lastJunkerShot = 0;  for (int i = 0; i &lt; 10; i++) asteroids[i].active = false;  for (int i = 0; i &lt; 5; i++) bullets[i].active = false;    for (int i = 0; i &lt; 4; i++) {    asteroids[i].active = true;    asteroids[i].x = random(0, 320); asteroids[i].y = random(0, 240);    float angle = random(0, 628) \/ 100.0;    asteroids[i].speedX = cos(angle) * 0.5; asteroids[i].speedY = sin(angle) * 0.5;    asteroids[i].size = 3;  }  tft.fillScreen(TFT_BLACK);}void drawUIJunker() {  tft.setTextColor(TFT_CYAN, TFT_BLACK);   tft.setCursor(5, 5);  tft.printf(\"SCORE:%d\", junkerScore);    tft.setTextColor(TFT_RED, TFT_BLACK);   tft.setCursor(260, 5);  tft.printf(\"LIVES:%d\", junkerLives);}void loopAsteroids() {  int val = analogRead(PIN_JOY_X);  if (val &lt; 300) junkerAngle -= 0.1;  if (val &gt; 700) junkerAngle += 0.1;  if (digitalRead(PIN_BTN_A) == LOW) {    junkerSpeedX += cos(junkerAngle) * 0.1;    junkerSpeedY += sin(junkerAngle) * 0.1;  }  if (junkerSpeedX &gt; 2) junkerSpeedX = 2; if (junkerSpeedX &lt; -2) junkerSpeedX = -2;  if (junkerSpeedY &gt; 2) junkerSpeedY = 2; if (junkerSpeedY &lt; -2) junkerSpeedY = -2;  junkerX += junkerSpeedX; junkerY += junkerSpeedY;  if (junkerX &lt; 0) junkerX = 320; if (junkerX &gt; 320) junkerX = 0;  if (junkerY &lt; 0) junkerY = 240; if (junkerY &gt; 240) junkerY = 0;  if (digitalRead(PIN_BTN_B) == LOW) {    if (millis() - lastJunkerShot &gt; 300) {       lastJunkerShot = millis();      for (int i = 0; i &lt; 5; i++) {        if (!bullets[i].active) {          bullets[i].active = true;          bullets[i].x = junkerX; bullets[i].y = junkerY;          bullets[i].speedX = cos(junkerAngle) * 4.0; bullets[i].speedY = sin(junkerAngle) * 4.0;          tone(BUZZER_PIN, 1200, 20);           break;        }      }    }  }  for (int i = 0; i &lt; 10; i++) {    if (asteroids[i].active) {      asteroids[i].x += asteroids[i].speedX; asteroids[i].y += asteroids[i].speedY;      if (asteroids[i].x &lt; 0) asteroids[i].x = 320; if (asteroids[i].x &gt; 320) asteroids[i].x = 0;      if (asteroids[i].y &lt; 0) asteroids[i].y = 240; if (asteroids[i].y &gt; 240) asteroids[i].y = 0;    }  }  for (int i = 0; i &lt; 5; i++) {    if (bullets[i].active) {      bullets[i].x += bullets[i].speedX; bullets[i].y += bullets[i].speedY;      if (bullets[i].x &lt; 0 || bullets[i].x &gt; 320 || bullets[i].y &lt; 0 || bullets[i].y &gt; 240) bullets[i].active = false;    }  }  for (int i = 0; i &lt; 5; i++) {    if (!bullets[i].active) continue;    for (int j = 0; j &lt; 10; j++) {      if (!asteroids[j].active) continue;      float dx = bullets[i].x - asteroids[j].x; float dy = bullets[i].y - asteroids[j].y;            if (sqrt(dx*dx + dy*dy) &lt; 15) {        bullets[i].active = false; asteroids[j].active = false; junkerScore += 10;         tone(BUZZER_PIN, (unsigned int)random(200, 400), 50);        if (asteroids[j].size &gt; 1) {          for (int k = 0; k &lt; 2; k++) {            for (int m = 0; m &lt; 10; m++) {              if (!asteroids[m].active) {                asteroids[m].active = true;                asteroids[m].x = asteroids[j].x; asteroids[m].y = asteroids[j].y;                float angle = random(0, 628) \/ 100.0;                asteroids[m].speedX = cos(angle) * (asteroids[j].size == 3 ? 1.0 : 1.5);                asteroids[m].speedY = sin(angle) * (asteroids[j].size == 3 ? 1.0 : 1.5);                asteroids[m].size = asteroids[j].size - 1;                break;              }            }          }        }        break;       }    }  }  for (int i = 0; i &lt; 10; i++) {    if (!asteroids[i].active) continue;    float dx = junkerX - asteroids[i].x; float dy = junkerY - asteroids[i].y;        if (sqrt(dx*dx + dy*dy) &lt; 15) {      junkerLives--; tone(BUZZER_PIN, 80, 500);       if (junkerLives &lt;= 0) { gameState = 0; return; }       else { junkerX = 160; junkerY = 120; junkerSpeedX = 0; junkerSpeedY = 0; delay(500); }    }  }  bool allDestroyed = true;  for (int i = 0; i &lt; 10; i++) {    if (asteroids[i].active) { allDestroyed = false; break; }  }    if (allDestroyed) {    junkerScore += 50;     tone(BUZZER_PIN, 2000, 200);         for (int i = 0; i &lt; 5; i++) {      asteroids[i].active = true;      asteroids[i].x = random(0, 320);       asteroids[i].y = random(0, 240);      float angle = random(0, 628) \/ 100.0;      asteroids[i].speedX = cos(angle) * 0.5;       asteroids[i].speedY = sin(angle) * 0.5;      asteroids[i].size = 3;    }  }  tft.fillScreen(TFT_BLACK);  for (int i = 0; i &lt; 10; i++) {    if (asteroids[i].active) {      int r = (asteroids[i].size == 3) ? 12 : (asteroids[i].size == 2 ? 8 : 4);      tft.drawCircle(asteroids[i].x, asteroids[i].y, r, TFT_WHITE);      if (asteroids[i].size == 1) tft.fillCircle(asteroids[i].x, asteroids[i].y, 2, TFT_WHITE);    }  }  for (int i = 0; i &lt; 5; i++) {    if (bullets[i].active) tft.fillRect(bullets[i].x, bullets[i].y, 2, 2, TFT_GREEN);  }  int noseX = junkerX + cos(junkerAngle) * 10; int noseY = junkerY + sin(junkerAngle) * 10;  int leftX = junkerX + cos(junkerAngle + 2.5) * 8; int leftY = junkerY + sin(junkerAngle + 2.5) * 8;  int rightX = junkerX + cos(junkerAngle - 2.5) * 8; int rightY = junkerY + sin(junkerAngle - 2.5) * 8;    tft.drawLine(noseX, noseY, leftX, leftY, TFT_CYAN);  tft.drawLine(noseX, noseY, rightX, rightY, TFT_CYAN);  tft.drawLine(leftX, leftY, rightX, rightY, TFT_CYAN);  drawUIJunker();  delay(5); }\/\/ ==========================================================\/\/ --- \u0411\u041b\u041e\u041a 4: \u0421\u041e\u0420\u0422\u0418\u0420\u041e\u0412\u0429\u0418\u041a ---\/\/ ==========================================================int sortPlayerX = 160;int sortScore = 0, sortLives = 3;struct SortItem { float x, y; int type; bool active; }; \/\/ type 1 - \u043a\u043d\u043e\u043f\u043a\u0430 \u0410, type 2 - \u043a\u043d\u043e\u043f\u043a\u0430 \u0411, type 3 - \u043c\u0443\u0441\u043e\u0440SortItem items[5];unsigned long lastSpawn = 0;void resetSorter() {  sortPlayerX = 160; sortScore = 0; sortLives = 3;  for(int i=0; i&lt;5; i++) items[i].active = false;  tft.fillScreen(TFT_BLACK);}void loopSorter() {  int val = analogRead(PIN_JOY_X);  if (val &lt; 400) sortPlayerX += 5;  if (val &gt; 600) sortPlayerX -= 5;  sortPlayerX = constrain(sortPlayerX, 10, 290);  \/\/ \u0421\u043f\u0430\u0432\u043d \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u0432  if (millis() - lastSpawn &gt; 800) {    lastSpawn = millis();    for (int i = 0; i &lt; 5; i++) {      if (!items[i].active) {        items[i].active = true;        items[i].x = random(30, 290);        items[i].y = 30;        items[i].type = random(1, 4); \/\/ 1, 2 \u0438\u043b\u0438 3        break;      }    }  }  \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043d\u043e\u043f\u043e\u043a  static bool lastA = HIGH; bool curA = digitalRead(PIN_BTN_A);  static bool lastB = HIGH; bool curB = digitalRead(PIN_BTN_B);  if (curA == LOW &amp;&amp; lastA == HIGH) { \/\/ \u041d\u0430\u0436\u0430\u043b\u0438 \u0410    for (int i = 0; i &lt; 5; i++) {      if (items[i].active &amp;&amp; items[i].y &gt; 180 &amp;&amp; abs(items[i].x - sortPlayerX) &lt; 30) {        if (items[i].type == 1) { sortScore += 10; tone(BUZZER_PIN, 1500, 100); }        else { sortLives--; tone(BUZZER_PIN, 200, 300); }        items[i].active = false;      }    }  }  if (curB == LOW &amp;&amp; lastB == HIGH) { \/\/ \u041d\u0430\u0436\u0430\u043b\u0438 \u0411    for (int i = 0; i &lt; 5; i++) {      if (items[i].active &amp;&amp; items[i].y &gt; 180 &amp;&amp; abs(items[i].x - sortPlayerX) &lt; 30) {        if (items[i].type == 2) { sortScore += 10; tone(BUZZER_PIN, 1500, 100); }        else { sortLives--; tone(BUZZER_PIN, 200, 300); }        items[i].active = false;      }    }  }  lastA = curA; lastB = curB;  \/\/ \u0414\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0430\u0434\u0435\u043d\u0438\u044f  for (int i = 0; i &lt; 5; i++) {    if (items[i].active) {      items[i].y += 1.5;      if (items[i].y &gt; 220) { \/\/ \u0423\u043f\u0430\u043b \u043d\u0430 \u043f\u043e\u043b (\u043d\u0435 \u043f\u043e\u0439\u043c\u0430\u043b\u0438)        if (items[i].type != 3) { sortLives--; tone(BUZZER_PIN, 100, 200); }        items[i].active = false;      }    }  }  if (sortLives &lt;= 0) { gameState = 0; return; }  \/\/ \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430  tft.fillScreen(TFT_BLACK);    \/\/ \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b  tft.fillRect(10, 200, 40, 40, TFT_RED); \/\/ \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0410  tft.fillRect(270, 200, 40, 40, TFT_BLUE); \/\/ \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0411  \/\/ \u0418\u0433\u0440\u043e\u043a  tft.fillRect(sortPlayerX - 15, 210, 30, 30, TFT_GREEN);  \/\/ \u041f\u0440\u0435\u0434\u043c\u0435\u0442\u044b  for (int i = 0; i &lt; 5; i++) {    if (items[i].active) {      if (items[i].type == 1) tft.fillCircle(items[i].x, items[i].y, 10, TFT_RED);      else if (items[i].type == 2) tft.fillRect(items[i].x - 10, items[i].y - 10, 20, 20, TFT_BLUE);      else tft.drawCircle(items[i].x, items[i].y, 10, TFT_WHITE); \/\/ \u041c\u0443\u0441\u043e\u0440 (\u043d\u0435 \u0442\u0440\u043e\u0433\u0430\u0442\u044c)    }  }  tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setCursor(5, 5);  tft.printf(\"SCORE:%d LIVES:%d\", sortScore, sortLives);  delay(20);}\/\/ ==========================================================\/\/ --- \u0411\u041b\u041e\u041a 5: \u0421\u041d\u0410\u0419\u041f\u0415\u0420 ---\/\/ ==========================================================int sniperX = 160, sniperScore = 0;struct Target { float x, y, speedX; int size; bool active; };Target targets[3];unsigned long lastTargetSpawn = 0;void resetSniper() {  sniperX = 160; sniperScore = 0;  for(int i=0; i&lt;3; i++) targets[i].active = false;  tft.fillScreen(TFT_BLACK);}void loopSniper() {  int val = analogRead(PIN_JOY_X);  if (val &lt; 400) sniperX += 5;  if (val &gt; 600) sniperX -=5;  sniperX = constrain(sniperX, 10, 310);  \/\/ \u0421\u043f\u0430\u0432\u043d \u043c\u0438\u0448\u0435\u043d\u0435\u0439  if (millis() - lastTargetSpawn &gt; 1000) {    lastTargetSpawn = millis();    for (int i = 0; i &lt; 3; i++) {      if (!targets[i].active) {        targets[i].active = true;        targets[i].x = random(20, 300);        targets[i].y = 50;        targets[i].speedX = (random(0, 2) == 0) ? 1.5 : -1.5; \/\/ \u041b\u0435\u0442\u0430\u044e\u0442 \u0432\u043b\u0435\u0432\u043e-\u0432\u043f\u0440\u0430\u0432\u043e        targets[i].size = random(10, 20); \/\/ \u0420\u0430\u0437\u043d\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440        break;      }    }  }  \/\/ \u0412\u044b\u0441\u0442\u0440\u0435\u043b  static bool lastA = HIGH; bool curA = digitalRead(PIN_BTN_A);  if (curA == LOW &amp;&amp; lastA == HIGH) {    tone(BUZZER_PIN, 800, 50);    for (int i = 0; i &lt; 3; i++) {      if (targets[i].active &amp;&amp; abs(targets[i].x - sniperX) &lt; targets[i].size) {        \/\/ \u041f\u043e\u043f\u0430\u043b        sniperScore += 20;        targets[i].active = false;        tone(BUZZER_PIN, 2000, 100); \/\/ \u0417\u0432\u0443\u043a \u043f\u043e\u0431\u0435\u0434\u044b        break;      }    }  }  lastA = curA;  \/\/ \u0414\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u043c\u0438\u0448\u0435\u043d\u0435\u0439  for (int i = 0; i &lt; 3; i++) {    if (targets[i].active) {      targets[i].x += targets[i].speedX;      if (targets[i].x &lt; 20 || targets[i].x &gt; 300) targets[i].speedX *= -1; \/\/ \u041e\u0442\u0441\u043a\u043e\u043a \u043e\u0442 \u043a\u0440\u0430\u0435\u0432    }  }  \/\/ \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430  tft.fillScreen(TFT_BLACK);    \/\/ \u041c\u0438\u0448\u0435\u043d\u0438  for (int i = 0; i &lt; 3; i++) {    if (targets[i].active) {      tft.drawCircle(targets[i].x, targets[i].y, targets[i].size, TFT_RED);      tft.fillCircle(targets[i].x, targets[i].y, 3, TFT_RED);    }  }  \/\/ \u041f\u0443\u0448\u043a\u0430 (\u0421\u043d\u0430\u0439\u043f\u0435\u0440)  tft.fillRect(sniperX - 5, 200, 10, 30, TFT_CYAN); \/\/ \u0421\u0442\u0432\u043e\u043b  tft.fillCircle(sniperX, 200, 10, TFT_CYAN);       \/\/ \u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435  tft.drawFastVLine(sniperX, 170, 30, TFT_GREEN);   \/\/ \u041b\u0430\u0437\u0435\u0440\u043d\u044b\u0439 \u043f\u0440\u0438\u0446\u0435\u043b  tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setCursor(5, 5);  tft.printf(\"SCORE:%d\", sniperScore);  delay(20);}\/\/ ==========================================================\/\/ --- \u0411\u041b\u041e\u041a 6: SETUP &amp; LOOP ---\/\/ ==========================================================void setup() {  EEPROM.begin(512); EEPROM.get(0, highScore);  pinMode(PIN_BTN_A, INPUT_PULLUP); pinMode(PIN_BTN_B, INPUT_PULLUP); pinMode(BUZZER_PIN, OUTPUT);  tft.init(); tft.setRotation(1);     randomSeed(analogRead(PIN_JOY_X));  for(int i=0; i&lt;40; i++) {    starX[i] = random(0, 320); starY[i] = random(0, 100);  }  generateMap();}void loop() {  if (gameState == 0) {    static unsigned long lastMenuMove = 0;    int xVal = analogRead(PIN_JOY_X);        if (millis() - lastMenuMove &gt; 250) {      if (xVal &lt; 400) {        menuSelection--;        if (menuSelection &lt; 1) menuSelection = 5;        lastMenuMove = millis();        tone(BUZZER_PIN, 500, 20);      }      if (xVal &gt; 600) {        menuSelection++;        if (menuSelection &gt; 5) menuSelection = 1;        lastMenuMove = millis();        tone(BUZZER_PIN, 500, 20);      }    }    tft.setTextColor(menuSelection == 1 ? TFT_GREEN : TFT_WHITE, TFT_BLACK);    tft.drawCentreString(\"1. RAYCAST\", 160, 20, 4);    tft.setTextColor(menuSelection == 2 ? TFT_GREEN : TFT_WHITE, TFT_BLACK);    tft.drawCentreString(\"2. INVADERS\", 160, 60, 4);    tft.setTextColor(menuSelection == 3 ? TFT_GREEN : TFT_WHITE, TFT_BLACK);    tft.drawCentreString(\"3. JUNKER\", 160, 100, 4);    tft.setTextColor(menuSelection == 4 ? TFT_GREEN : TFT_WHITE, TFT_BLACK);    tft.drawCentreString(\"4. SORTER\", 160, 140, 4);    tft.setTextColor(menuSelection == 5 ? TFT_GREEN : TFT_WHITE, TFT_BLACK);    tft.drawCentreString(\"5. SNIPER\", 160, 180, 4);    if (digitalRead(PIN_BTN_A) == LOW) {       gameState = menuSelection;       tft.fillScreen(TFT_BLACK);       if(gameState == 2) resetInvadersLevel();       if(gameState == 3) resetAsteroids();      if(gameState == 4) resetSorter();      if(gameState == 5) resetSniper();      delay(300);     }  }   else if (gameState == 1) loopRaycast();  else if (gameState == 2) loopInvaders();  else if (gameState == 3) loopAsteroids();  else if (gameState == 4) loopSorter();  else if (gameState == 5) loopSniper();  if (digitalRead(PIN_BTN_A) == LOW &amp;&amp; digitalRead(PIN_BTN_B) == LOW) {    delay(1000);     if (digitalRead(PIN_BTN_A) == LOW &amp;&amp; digitalRead(PIN_BTN_B) == LOW) {       gameState = 0; tft.fillScreen(TFT_BLACK); delay(500);     }  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1097380\/\">https:\/\/habr.com\/ru\/articles\/1097380\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b \u043f\u0440\u043e \u0436\u0435\u043b\u0435\u0437\u043e, \u0441\u0431\u043e\u0440\u043a\u0443 \u043a\u043e\u0440\u043f\u0443\u0441\u0430 \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u043b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0437\u0430\u0433\u043b\u044f\u043d\u0435\u043c \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0443, \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e\u0434 \u0441\u043b\u0430\u0431\u043e\u0435 \u0436\u0435\u043b\u0435\u0437\u043e.\u041a\u043e\u0434 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 C++ \u0432 Arduino IDE, \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0436\u0438\u0432\u0435\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435. \u0423 \u043d\u0430\u0441 \u0443\u0436\u0435 \u043f\u044f\u0442\u044c \u0438\u0433\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043e\u043c \u0447\u0435\u0440\u0435\u0437 gameState.\u0411\u043b\u043e\u043a 1: Raycast \u2014 3D \u043d\u0430 \u043a\u043e\u043b\u0435\u043d\u043a\u0435\u0421\u0435\u0440\u0434\u0446\u0435 \u0434\u0432\u0438\u0436\u043a\u0430 \u2014 DDA-\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c (Digital Differential Analyzer). \u041c\u044b \u043d\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043c 3D-\u043f\u043e\u043b\u0438\u0433\u043e\u043d\u044b, \u043c\u044b \u043f\u0443\u0441\u043a\u0430\u0435\u043c 320 \u043b\u0443\u0447\u0435\u0439 \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 \u0438\u0433\u0440\u043e\u043a\u0430 \u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0433\u0434\u0435 \u043e\u043d\u0438 \u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430\u044e\u0442 \u0441\u0435\u0442\u043a\u0443 32&#215;32.\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044buint8_t worldMap[1024]; \/\/ 32&#215;32\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c uint8_t (1 \u0431\u0430\u0439\u0442), \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u044f \u043a\u0430\u0440\u0442\u0430 \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u0430 \u0440\u043e\u0432\u043d\u043e 1 \u041a\u0411 RAM.\u0418\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f \u0438\u0434\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 y * 32 + x. \u041d\u043e\u043b\u044c \u2014 \u043f\u0443\u0441\u0442\u0430\u044f \u043a\u043b\u0435\u0442\u043a\u0430, \u0435\u0434\u0438\u043d\u0438\u0446\u0430 \u2014 \u0441\u0442\u0435\u043d\u0430, \u0434\u0432\u043e\u0439\u043a\u0430 \u2014 \u0431\u0430\u0437\u0430, \u0442\u0440\u043e\u0439\u043a\u0430 \u2014 \u043a\u0443\u0431\u0438\u043a.for(int x=0; x&lt;320; x+=2){ESP8266 \u043d\u0435 \u0443\u0441\u043f\u0435\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u043e SPI 320 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043b\u0438\u043d\u0438\u0439 \u0437\u0430 \u043a\u0430\u0434\u0440.\u0420\u0438\u0441\u0443\u044f 160 \u043b\u0438\u043d\u0438\u0439 \u0438 \u0440\u0430\u0441\u0442\u044f\u0433\u0438\u0432\u0430\u044f \u0438\u0445 \u043d\u0430 \u0434\u0432\u0430 \u043f\u0438\u043a\u0441\u0435\u043b\u044f (drawFastVLine(x, &#8230;) \u0438 drawFastVLine(x+1, &#8230;)), \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0432\u0443\u043a\u0440\u0430\u0442\u043d\u044b\u0439 \u043f\u0440\u0438\u0440\u043e\u0441\u0442 FPS. \u041d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 2.4 \u0434\u044e\u0439\u043c\u0430 \u043f\u043e\u0442\u0435\u0440\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430 \u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439 \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u0430 \u0433\u043b\u0430\u0437\u0443. \u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430 \u043b\u0443\u0447\u0430 (DDA)  float camX = 2.0*x\/320.0-1.0; \/\/ \u041e\u0442 -1 \u0434\u043e 1 (\u043e\u0442 \u043b\u0435\u0432\u043e\u0433\u043e \u043a\u0440\u0430\u044f \u0434\u043e \u043f\u0440\u0430\u0432\u043e\u0433\u043e)float rDX = dirX+planeX*camX, rDY = dirY+planeY*camX;float dDX = abs(1.0\/rDX), dDY = abs(1.0\/rDY); \/\/ \u0414\u043b\u0438\u043d\u0430 \u0448\u0430\u0433\u0430 \u043f\u043e \u0441\u0435\u0442\u043a\u0435\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 dDX \u0438 dDY \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442, \u043a\u0430\u043a\u043e\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u043e \u043b\u0443\u0447\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u044c \u043e\u0434\u043d\u0443 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043b\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u043b\u0438\u043d\u0438\u044e \u0441\u0435\u0442\u043a\u0438.\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0448\u0430\u0433\u0430\u0435\u0442 \u0432 \u0446\u0438\u043a\u043b\u0435 while(!hit), \u0432\u044b\u0431\u0438\u0440\u0430\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043a\u0440\u0430\u0442\u0447\u0430\u0439\u0448\u0438\u0439 \u043f\u0443\u0442\u044c (\u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043b\u0438 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0439). \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e worldMap \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 &gt;0 \u2014 \u043c\u044b \u043f\u043e\u043f\u0430\u043b\u0438 \u0432 \u0441\u0442\u0435\u043d\u0443.\u042d\u0444\u0444\u0435\u043a\u0442 \u0440\u044b\u0431\u044c\u0435\u0433\u043e \u0433\u043b\u0430\u0437\u0430float pdist = (side == 0) ? (sDX &#8212; dDX) : (sDY &#8212; dDY);int lh = (int)(240 \/ pdist);\u0415\u0441\u043b\u0438 \u043d\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0441\u0442\u0435\u043d\u044b \u0432 \u0446\u0435\u043d\u0442\u0440\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u0431\u0443\u0434\u0443\u0442 \u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0432\u044b\u043f\u0443\u043a\u043b\u044b\u043c\u0438.\u0424\u043e\u0440\u043c\u0443\u043b\u0430 (sDX &#8212; dDX) \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u043f\u0435\u043d\u0434\u0438\u043a\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043e \u0441\u0442\u0435\u043d\u044b, \u0443\u0431\u0438\u0440\u0430\u044f \u0438\u0441\u043a\u0430\u0436\u0435\u043d\u0438\u0435.\u0422\u0435\u043a\u0441\u0442\u0443\u0440\u0430 \u0441\u0442\u0435\u043dfloat wallX = (side == 0) ? (posY + pdist * rDY) : (posX + pdist * rDX);wallX -= floor(wallX); if (wallX &lt; 0.05f || wallX &gt; 0.95f) bC = 0x5AEB; else bC = (side==1?0x7BEF:0xFFFF);               \u041c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0442\u043e\u0447\u043a\u0443 \u043f\u043e\u043f\u0430\u0434\u0430\u043d\u0438\u044f \u0432 \u0441\u0442\u0435\u043d\u0443, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c (wallX \u043e\u0442 0.0 \u0434\u043e 1.0).\u0415\u0441\u043b\u0438 \u043b\u0443\u0447 \u043f\u043e\u043f\u0430\u043b \u0432 \u043a\u043b\u0435\u0442\u043a\u0443 \u0443 \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u0440\u0430\u044f, \u0440\u0438\u0441\u0443\u0435\u043c \u0442\u0435\u043c\u043d\u044b\u0439 \u0448\u043e\u0432. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0438\u043b\u043b\u044e\u0437\u0438\u044e \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u044b \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u043d\u044b\u0445 \u0441\u043f\u0440\u0430\u0439\u0442\u043e\u0432, \u044d\u043a\u043e\u043d\u043e\u043c\u044f \u043f\u0430\u043c\u044f\u0442\u044c.\u042d\u0444\u0444\u0435\u043a\u0442 \u0444\u043e\u043d\u0430\u0440\u044f (RGB565)uint16_t applyLantern(uint16_t color, float dist) {  uint8_t r = (color &gt;&gt; 11) &amp; 0x1F;  uint8_t g = (color &gt;&gt; 5) &amp; 0x3F;  uint8_t b = color &amp; 0x1F;  float factor = 1.0 &#8212; (dist \/ 12.0);  return tft.color565(r * factor * 8, g * factor * 4, b * factor * 8);}\u0414\u0438\u0441\u043f\u043b\u0435\u0439 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 16-\u0431\u0438\u0442\u043d\u044b\u0439 \u0446\u0432\u0435\u0442.\u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u0442\u0443\u0445\u0430\u043d\u0438\u0435, \u043c\u044b \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u0446\u0432\u0435\u0442 \u043d\u0430 R, G, B \u043f\u043e\u0431\u0438\u0442\u043e\u0432\u044b\u043c\u0438 \u0441\u0434\u0432\u0438\u0433\u0430\u043c\u0438, \u0443\u043c\u043d\u043e\u0436\u0430\u0435\u043c \u043d\u0430 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043c\u043d\u043e\u0436\u0438\u043b\u0430 \u0431\u044b 16-\u0431\u0438\u0442\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e, \u0438 \u0446\u0432\u0435\u0442\u0430 \u0431\u044b \u00ab\u043f\u043e\u043f\u043b\u044b\u043b\u0438\u00bb.\u0417\u0432\u0435\u0437\u0434\u044b \u0438 HUDif (starY[i] &lt; topWall[starX[i]]) tft.drawPixel(starX[i], starY[i], TFT_WHITE);\u0427\u0442\u043e\u0431\u044b \u0437\u0432\u0435\u0437\u0434\u044b \u043d\u0435 \u043f\u0440\u043e\u0441\u0432\u0435\u0447\u0438\u0432\u0430\u043b\u0438 \u0441\u043a\u0432\u043e\u0437\u044c \u0441\u0442\u0435\u043d\u044b, \u043c\u044b \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0441\u0442\u0435\u043d \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c \u0432\u044b\u0441\u043e\u0442\u0443 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0442\u043e\u0447\u043a\u0438 \u0441\u0442\u0435\u043d\u044b \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 topWall[x].\u041f\u0440\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0435 \u0437\u0432\u0435\u0437\u0434\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0438\u0436\u0435 \u043b\u0438 \u043e\u043d\u0430 \u0441\u0442\u0435\u043d\u044b. \u0415\u0441\u043b\u0438 \u0434\u0430 \u2014 \u043d\u0435 \u0440\u0438\u0441\u0443\u0435\u043c. HUD (Lvl:&#8230; Items:&#8230;) \u0432\u044b\u043d\u0435\u0441\u0435\u043d \u0432 \u0441\u0430\u043c\u044b\u0439 \u043a\u043e\u043d\u0435\u0446, \u0447\u0442\u043e\u0431\u044b \u0435\u0433\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u043b\u0438 \u0441\u0442\u0435\u043d\u044b.\u041a\u043e\u043b\u043b\u0438\u0437\u0438\u0438 \u0438 \u0431\u0430\u0433 \u00ab\u0437\u0430\u0441\u0442\u0440\u0435\u0432\u0430\u043d\u0438\u044f\u00bbint nextX = (int)(posX + dirX*0.3);if(worldMap[(int)posY*32 + nextX] != 1 &amp;&amp; worldMap[(int)posY*32 + nextX] != 2) posX += dirX*ms;\u0422\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 (\u0438 \u044f \u043d\u0430 \u044d\u0442\u0438 \u0436\u0435 \u0433\u0440\u0430\u0431\u043b\u0438 \u043d\u0430\u0441\u0442\u0443\u043f\u0438\u043b, \u0447\u0435\u0433\u043e \u0433\u0440\u0435\u0445\u0430 \u0442\u0430\u0438\u0442\u044c..) \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u044e \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043a\u043b\u0435\u0442\u043a\u0435. \u0415\u0441\u043b\u0438 \u0438\u0433\u0440\u043e\u043a \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0432 \u0441\u0442\u0435\u043d\u0435, \u043e\u043d \u0437\u0430\u0441\u0442\u0440\u0435\u0432\u0430\u0435\u0442 \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430.\u041c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043b\u0435\u0442\u043a\u0443 (nextX, nextY), \u0440\u0430\u0437\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e \u043e\u0441\u044f\u043c X \u0438 Y. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u00ab\u0441\u043a\u043e\u043b\u044c\u0437\u0438\u0442\u044c\u00bb \u0432\u0434\u043e\u043b\u044c \u0441\u0442\u0435\u043d. \u0411\u043b\u043e\u043a 2: Space Invaders \u2014 \u0411\u043e\u0441\u0441\u044b \u0438 \u0431\u043e\u043d\u0443\u0441\u044b   \u0414\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u0437\u0438\u0433\u0437\u0430\u0433\u043e\u043c  if (millis() &#8212; lastAlienMove &gt; 500) {  alienX += (10 * alienDir);   if (alienX &gt; 180 || alienX &lt; 5) { alienDir *= -1; alienY += 10; }}\u041f\u0440\u0438\u0448\u0435\u043b\u044c\u0446\u044b \u0434\u0432\u0438\u0433\u0430\u044e\u0442\u0441\u044f \u0433\u0440\u0443\u043f\u043f\u043e\u0439. \u041a\u043e\u0433\u0434\u0430 \u0433\u0440\u0443\u043f\u043f\u0430 \u0443\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u0440\u0430\u0439 \u044d\u043a\u0440\u0430\u043d\u0430, \u043c\u044b \u043c\u0435\u043d\u044f\u0435\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0435\u0435 \u0432\u043d\u0438\u0437 \u043d\u0430 10 \u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439.\u0411\u043e\u043d\u0443\u0441\u044b \u0438 \u0430\u043d\u0442\u0438\u0431\u043e\u043d\u0443\u0441\u044bif (!bonusActive &amp;&amp; random(5) == 1) {   bonusActive = true;   bonusType = random(1, 4); }\u0421 \u0448\u0430\u043d\u0441\u043e\u043c 20% (1 \u043a 5) \u0438\u0437 \u0441\u0431\u0438\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0448\u0435\u043b\u044c\u0446\u0430 \u0432\u044b\u043f\u0430\u0434\u0430\u0435\u0442 \u0431\u043e\u043d\u0443\u0441.\u0422\u0438\u043f\u044b \u0431\u043e\u043d\u0443\u0441\u043e\u0432:\u0416\u0438\u0437\u043d\u044c: \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0436\u0438\u0437\u043d\u044c (lives++).\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435: \u0423\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 (rapidFireTimer = millis()+5000).\u0410\u043d\u0442\u0438\u0431\u043e\u043d\u0443\u0441: \u0423\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0435\u043b\u044c\u0431\u0430 \u0432\u0440\u0430\u0433\u043e\u0432 (enemyRapidFireTimer = millis()+5000).\u0411\u043e\u0441\u0441 \u0438 \u0441\u0438\u043d\u0443\u0441\u043e\u0438\u0434\u0430int wave = sin(millis()*0.005)*10;tft.fillTriangle(bossX+5, bossY+20, bossX+8, bossY+20, bossX+5+wave, bossY+35, TFT_RED);\u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0440\u0435\u0442\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u2014 \u0431\u043e\u0441\u0441. \u0415\u0433\u043e \u0449\u0443\u043f\u0430\u043b\u044c\u0446\u0430 (\u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0438) \u043a\u0430\u0447\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0441\u0438\u043d\u0443\u0441\u043e\u0438\u0434\u0435 \u043e\u0442 millis(). \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442 \u0436\u0438\u0432\u043e\u0433\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043c\u0430 \u0431\u0435\u0437 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0441\u043f\u0440\u0430\u0439\u0442\u043e\u0432.\u041f\u0440\u0438 \u0441\u043c\u0435\u0440\u0442\u0438 \u0431\u043e\u0441\u0441\u0430 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0446\u0438\u043a\u043b \u0438\u0437 15 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439:tft.fillCircle(rx, ry, random(5, 15), TFT_WHITE);tone(BUZZER_PIN, (unsigned int)random(100, 800), 40);\u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442 \u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043a\u0440\u0443\u0433\u043e\u0432 \u0438 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u0437\u0432\u0443\u043a\u043e\u0432 \u2014 \u043a\u043b\u0430\u0441\u0441\u0438\u043a\u0430 \u0441\u0442\u0430\u0440\u044b\u0445 \u0430\u0440\u043a\u0430\u0434. \u0411\u043b\u043e\u043a 3: Space Junker (Asteroids) \u2014 \u0418\u043d\u0435\u0440\u0446\u0438\u044f \u0438 \u0444\u0438\u0437\u0438\u043a\u0430   \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445  struct Asteroid { float x, y; float speedX, speedY; int size; bool active; };struct Bullet { float x, y; float speedX, speedY; bool active; }; \u0412\u043c\u0435\u0441\u0442\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432 float asteroidX[10] \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b. \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u043e\u0434 \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c, \u0430 \u043f\u0430\u043c\u044f\u0442\u044c \u0440\u0430\u0441\u0445\u043e\u0434\u0443\u0435\u0442\u0441\u044f \u0442\u0430\u043a \u0436\u0435.   \u0418\u043d\u0435\u0440\u0446\u0438\u044f \u0432 \u0432\u0430\u043a\u0443\u0443\u043c\u0435  if (digitalRead(PIN_BTN_A) == LOW) {  junkerSpeedX += cos(junkerAngle) * 0.1;  junkerSpeedY += sin(junkerAngle) * 0.1;}\u0412 \u043a\u043e\u0441\u043c\u043e\u0441\u0435 \u043d\u0435\u0442 \u0442\u0440\u0435\u043d\u0438\u044f. \u041d\u0430\u0436\u0430\u043b \u043d\u0430 \u0442\u044f\u0433\u0443 \u2014 \u043a\u043e\u0440\u0430\u0431\u043b\u044c \u0443\u0441\u043a\u043e\u0440\u0438\u043b\u0441\u044f. \u041e\u0442\u043f\u0443\u0441\u0442\u0438\u043b \u2014 \u043b\u0435\u0442\u0438\u0442 \u043f\u043e \u0438\u043d\u0435\u0440\u0446\u0438\u0438.\u041c\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c (if (junkerSpeedX &gt; 2) junkerSpeedX = 2;), \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u0440\u0430\u0431\u043b\u044c \u043d\u0435 \u0443\u043b\u0435\u0442\u0430\u043b \u0437\u0430 \u043a\u0430\u0434\u0440 \u0437\u0430 \u043e\u0434\u043d\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438. \u0422\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u044f  if (junkerX &lt; 0) junkerX = 320; if (junkerX &gt; 320) junkerX = 0;\u0423\u043b\u0435\u0442\u0435\u043b \u0437\u0430 \u043f\u0440\u0430\u0432\u044b\u0439 \u043a\u0440\u0430\u0439 \u2014 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0441\u043b\u0435\u0432\u0430. \u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0433\u0440\u0435 \u0434\u0438\u043d\u0430\u043c\u0438\u043a\u0438.\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0441\u0442\u0440\u0435\u043b\u044c\u0431\u0430 (\u0422\u0430\u0439\u043c\u0435\u0440)if (digitalRead(PIN_BTN_B) == LOW) {  if (millis() &#8212; lastJunkerShot &gt; 200) {     lastJunkerShot = millis();    \/\/ &#8230; \u0432\u044b\u043b\u0435\u0442 \u043f\u0443\u043b\u0438 &#8230;  }}\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043d\u0430\u0436\u0438\u043c\u0430\u0442\u044c \u0431\u0435\u0437 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 , \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0430\u0439\u043c\u0435\u0440 millis().\u0417\u0430\u0436\u0430\u043b \u043a\u043d\u043e\u043f\u043a\u0443 \u2014 \u0441\u0442\u0440\u0435\u043b\u044f\u0435\u0448\u044c \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 5 \u0432\u044b\u0441\u0442\u0440\u0435\u043b\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443. delay() \u0442\u0443\u0442 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442, \u043e\u043d \u0431\u044b \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u043b \u0438\u0433\u0440\u0443.\u0414\u0440\u043e\u0431\u043b\u0435\u043d\u0438\u0435 \u0430\u0441\u0442\u0435\u0440\u043e\u0438\u0434\u043e\u0432if (asteroids[j].size &gt; 1) {  for (int k = 0; k &lt; 2; k++) {    asteroids[m].size = asteroids[j].size &#8212; 1;    asteroids[m].speedX = cos(angle) * (asteroids[j].size == 3 ? 1.0 : 1.5);  }}\u041f\u0443\u043b\u044f \u043f\u043e\u043f\u0430\u043b\u0430 \u0432 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0430\u0441\u0442\u0435\u0440\u043e\u0438\u0434? \u041e\u043d \u043d\u0435 \u0438\u0441\u0447\u0435\u0437\u0430\u0435\u0442, \u0430 \u0441\u043f\u0430\u0432\u043d\u0438\u0442 \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445, \u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 (size &#8212; 1).\u041e\u0441\u043a\u043e\u043b\u043a\u0438 \u043b\u0435\u0442\u044f\u0442 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0438 \u0441 \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0445\u0430\u043e\u0441 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435.\u0411\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0441\u043f\u0430\u0432\u043dbool allDestroyed = true;for (int i = 0; i &lt; 10; i++) if (asteroids[i].active) allDestroyed = false;if (allDestroyed) { junkerScore += 50; \/* \u0421\u043f\u0430\u0432\u043d \u043d\u043e\u0432\u043e\u0439 \u0432\u043e\u043b\u043d\u044b *\/ }\u041d\u0430 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u0438 \u0430\u0441\u0442\u0435\u0440\u0438\u0434\u043e\u0432 \u0438\u0433\u0440\u0430 \u043d\u0435 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.\u041c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u043b\u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u0438 \u0435\u0441\u043b\u0438 \u0438\u0445 \u043d\u0435\u0442 \u2014 \u0441\u043f\u0430\u0432\u043d\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u0432\u043e\u043b\u043d\u0443 \u0438 \u0434\u0430\u0435\u043c \u0431\u043e\u043d\u0443\u0441\u043d\u044b\u0435 \u043e\u0447\u043a\u0438. \u0418\u0442\u043e\u0433   \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u044d\u0439\u043a\u0430\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f 3D, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0438 \u0442\u0440\u0438\u0433\u043e\u043d\u043e\u043c\u0435\u0442\u0440\u0438\u044e \u0434\u043b\u044f \u00ab\u0410\u0441\u0442\u0435\u0440\u043e\u0438\u0434\u043e\u0432\u00bb, \u0438 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0451 \u044d\u0442\u043e \u0434\u0440\u0443\u0436\u0438\u043b\u043e \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439. \u0418 \u0434\u0430, \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0438\u0433\u0440 \u0438 \u0438\u0445 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u043f\u043e \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u0438 \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0438\u0437\u043d\u0435\u0441\u0435\u043d\u043e \u043d\u0435\u043c\u0430\u043b\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043a\u043b\u0438\u043d\u0430\u043d\u0438\u0439.. \u0421\u0442\u0438\u0432 \u0437\u0430\u0441\u0442\u0440\u0435\u0432\u0430\u043b \u0432 \u0442\u0435\u043a\u0441\u0442\u0443\u0440\u0430\u0445, \u0441\u043f\u0430\u0432\u043d\u0438\u043b\u0441\u044f \u0432 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0435 \u043c\u0435\u0436\u0434\u0443 \u0441\u0442\u0435\u043d\u043e\u0439 \u0438 \u0431\u0430\u0437\u043e\u0439 \u0432 \u0441\u0430\u043c\u043e\u043c \u0443\u0433\u043b\u0443 \u0438 \u043d\u0435 \u043c\u043e\u0433 \u0432\u044b\u0439\u0442\u0438&#8230; \u0417\u0430\u0431\u043e\u0440 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u0430\u0432\u043e\u043a \u0432 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u0445 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u043a\u0443\u0431\u0438\u043a\u043e\u0432 \u043d\u0430\u0440\u0435\u0437\u0430\u043b\u0441\u044f \u043d\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b, \u043a\u0430\u043a \u0438 \u0441\u0430\u043c\u0438 \u043a\u0443\u0431\u0438\u043a\u0438&#8230; \u042d\u0442\u0438 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u044f \u043e\u043f\u0443\u0441\u0442\u0438\u043b. \u041d\u043e \u0441\u0430\u043c\u044b\u0439 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0431\u0430\u0433, \u044f \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u0431\u0435\u0434\u0438\u043b. \u0421\u0442\u0438\u0432 \u043c\u0435\u0440\u0446\u0430\u0435\u0442. \u0427\u0442\u043e \u0431\u044b \u044f \u043d\u0435 \u0434\u0435\u043b\u0430\u043b. \u0414\u0430\u0436\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0432 \u0435\u0433\u043e \u0432 HUD, \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u043a \u0441\u043b\u043e\u0432\u0443, \u0442\u043e\u0436\u0435 \u043c\u0435\u0440\u0446\u0430\u0435\u0442. \u0421\u043c\u0438\u0440\u0438\u043b\u0441\u044f \u0432 \u0438\u0442\u043e\u0433\u0435 \u0438 \u043e\u0442\u043d\u043e\u0448\u0443\u0441\u044c \u043a\u0430\u043a \u043a \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u043e\u043c\u0443 \u0437\u043b\u0443..\u041f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0421\u0442\u0438\u0432\u0430 \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0435 \u043f\u043e\u0434 \u0446\u0432\u0435\u0442 \u043f\u043e\u043b\u0430  \u042d\u0442\u043e \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435 \u0431\u0430\u0437\u0443, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0421\u0442\u0438\u0432 \u043d\u043e\u0441\u0438\u0442 \u043a\u0443\u0431\u0438\u043a\u0438\u041f\u043e\u043f\u044b\u0442\u043a\u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a\u0438\u0412\u043e\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. #include &lt;SPI.h&gt;#include &lt;TFT_eSPI.h&gt;#include &lt;EEPROM.h&gt;TFT_eSPI tft = TFT_eSPI();\/\/ &#8212; \u041f\u0418\u041d\u042b \u0418 \u041d\u0410\u0421\u0422\u0420\u041e\u0419\u041a\u0418 &#8212;#define PIN_JOY_X A0#define PIN_BTN_A D3 #define PIN_BTN_B D0 #define BUZZER_PIN D6#define SKIN 0xFD42#define SHIRT 0x255A#define PANTS 0x2235\/\/ \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435int gameState = 0, menuSelection = 1;bool isPaused = false, lastBtnBState = HIGH;\/\/ ==========================================================\/\/ &#8212; \u0411\u041b\u041e\u041a 1: RAYCAST (MINECRAFT) &#8212;\/\/ ==========================================================float posX = 2.5, posY = 2.5, dirX = 1.0, dirY = 0.0, planeX = 0.0, planeY = 0.66;bool hasItem = false; int itemsInBase = 0, totalItemsInLevel = 10, currentLevel = 1;uint8_t worldMap[1024]; int starX[40], starY[40];int topWall[320]; void generateMap() {  for(int i=0; i&lt;1024; i++) worldMap[i] = 0;  for(int i=0; i&lt;32; i++) { worldMap[i]=1; worldMap[992+i]=1; worldMap[i*32]=1; worldMap[i*32+31]=1; }  for(int i=6; i&lt;26; i++) { worldMap[16*32+i]=1; worldMap[i*32+16]=1; }    \/\/ \u0411\u0410\u0417\u0410 (2) \u0412 \u0426\u0415\u041d\u0422\u0420\u0415  worldMap[10*32+10]=2; worldMap[10*32+11]=2;   worldMap[11*32+10]=2; worldMap[11*32+11]=2;  int count = 0;   while(count &lt; totalItemsInLevel) {    int rx = random(1, 31), ry = random(1, 31);    if(worldMap[ry*32+rx] == 0) { worldMap[ry*32+rx] = 3; count++; }  }}uint16_t applyLantern(uint16_t color, float dist) {  float range = 12.0; if(dist &gt; range) return TFT_BLACK;  uint8_t r = (color &gt;&gt; 11) &amp; 0x1F, g = (color &gt;&gt; 5) &amp; 0x3F, b = color &amp; 0x1F;  float factor = 1.0 &#8212; (dist \/ range); return tft.color565(r * factor * 8, g * factor * 4, b * factor * 8);}void loopRaycast() {  int val = analogRead(PIN_JOY_X);  float rot = (val &lt; 400) ? 0.07 : (val &gt; 600 ? -0.07 : 0);  if (rot != 0) {    float odX = dirX; dirX = dirX*cos(rot)-dirY*sin(rot); dirY = odX*sin(rot)+dirY*cos(rot);    float opX = planeX; planeX = planeX*cos(rot)-planeY*sin(rot); planeY = opX*sin(rot)+planeY*cos(rot);  }    if (digitalRead(PIN_BTN_A) == LOW) {    float ms = 0.1;     int nextX = (int)(posX + dirX*0.3);    int nextY = (int)(posY + dirY*0.3);    if(worldMap[(int)posY*32 + nextX] != 1 &amp;&amp; worldMap[(int)posY*32 + nextX] != 2) posX += dirX*ms;    if(worldMap[nextY*32 + (int)posX] != 1 &amp;&amp; worldMap[nextY*32 + (int)posX] != 2) posY += dirY*ms;  }    static&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-499667","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/499667","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=499667"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/499667\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=499667"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=499667"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=499667"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}