#include #if defined( LGFX_M5STACK ) || defined( ARDUINO_M5Stack_Core_ESP32 ) || defined( ARDUINO_M5STACK_FIRE ) // M5Stack #define BUTTON_A_PIN 39 #define BUTTON_B_PIN 38 static constexpr std::uint32_t draw_cycle = 3; static constexpr float zoom_min = 2; static constexpr float zoom_max = 32; #elif defined( LGFX_M5STACK_CORE2 ) || defined( ARDUINO_M5STACK_Core2 ) #define BUTTON_A_PIN -1 #define BUTTON_B_PIN -1 static constexpr std::uint32_t draw_cycle = 3; static constexpr float zoom_min = 2; static constexpr float zoom_max = 32; #elif defined ( LGFX_M5STICKC ) || defined ( ARDUINO_M5Stick_C ) #define BUTTON_A_PIN 37 #define BUTTON_B_PIN 39 static constexpr std::uint32_t draw_cycle = 1; static constexpr float zoom_min = 1.4; static constexpr float zoom_max = 16; #elif defined( LGFX_ODROID_GO ) || defined( ARDUINO_ODROID_ESP32 ) // ODROID-GO #define BUTTON_A_PIN 32 #define BUTTON_B_PIN 33 static constexpr std::uint32_t draw_cycle = 3; static constexpr float zoom_min = 2; static constexpr float zoom_max = 32; #elif defined( LGFX_TTGO_TWATCH ) || defined( ARDUINO_T ) // TTGO T-Watch #define BUTTON_A_PIN 36 #define BUTTON_B_PIN -1 static constexpr std::uint32_t draw_cycle = 2; static constexpr float zoom_min = 2; static constexpr float zoom_max = 32; #elif defined( LGFX_WIO_TERMINAL ) || defined (ARDUINO_WIO_TERMINAL) || defined(WIO_TERMINAL) #define BUTTON_A_PIN 0x0200|28 #define BUTTON_B_PIN 0x0200|27 static constexpr std::uint32_t draw_cycle = 3; static constexpr float zoom_min = 2; static constexpr float zoom_max = 32; #endif static LGFX lcd; static LGFX_Sprite sp(&lcd); static std::int32_t px, py; static float ox, oy; static float cx, cy, cr; static float ax, ay; static float zoom; static float angle, rad; static float add_angle = 0; static float add_advance = 0; static std::uint32_t draw_count = 0; static std::uint32_t skip_count = 0; static constexpr float deg_to_rad = 0.017453292519943295769236907684886; static constexpr float gravity = -0.005; static constexpr float zoom_speed = 0.02; static void create_maze(void) { sp.clear(0); sp.setColor(1); sp.fillRect(0, 0, sp.width(), 16); sp.fillRect(0, sp.height() - 16, sp.width(), 16); sp.fillRect( 0, 0, 16, sp.height()-16); sp.fillRect(sp.width()-16, 0, 16, sp.height()-16); sp.setColor(3); for (int y = 1; y < sp.height(); y += 2) { for (int x = 1; x < sp.width(); x += 2) { sp.writePixel(x, y); int xx = x; int yy = y; do { xx = x; yy = y; switch (random(4)) { case 0: xx = x + 1; break; case 1: xx = x - 1; break; case 2: yy = y + 1; break; case 3: yy = y - 1; break; } } while (3 == sp.readPixelValue(xx, yy)); sp.writePixel(xx, yy); } } } static void draw(void) { draw_count += draw_cycle; std::uint_fast8_t blink = 127+abs(((int)(draw_count<<1) & 255)-128); sp.setPaletteColor(1, 127, 127, blink); sp.setPaletteColor(2, 127, blink, 127); float fx = (cx - ox); float fy = (cy - oy); float len = sqrtf(fx * fx + fy * fy) * zoom; float theta = atan2f(fx, fy) + rad; sp.pushRotateZoom(px - sinf(theta) * len, py - cosf(theta) * len, angle, zoom, zoom); } static void game_init(void) { px = lcd.width()>>1; py = lcd.height()/3; create_maze(); ox = sp.getPivotX(); oy = sp.getPivotY(); cx = (sp.width() >>1); cy = (sp.height()>>1); cr = 0.2; zoom = zoom_min; } static bool game_main(void) { std::int32_t tx, ty, tc; tc = lcd.getTouch(&tx, &ty); if ((BUTTON_A_PIN >=0 && BUTTON_B_PIN >=0 && (lgfx::gpio_in(BUTTON_A_PIN) == 0 && lgfx::gpio_in(BUTTON_B_PIN) == 0)) || tc > 1) { zoom *= 1.0 - zoom_speed; if (zoom < zoom_min) { zoom = zoom_min; } } else { zoom *= 1.0 + zoom_speed; if (zoom > zoom_max) { zoom = zoom_max; } add_angle -= add_angle / 10; if (tc) { add_angle += (tx > lcd.width()>>1) ? 0.6 : -0.6; } else if (BUTTON_A_PIN >= 0 && BUTTON_B_PIN >= 0) { if (BUTTON_A_PIN >=0 && lgfx::gpio_in(BUTTON_A_PIN) == 0) add_angle += 0.6; if (BUTTON_B_PIN >=0 && lgfx::gpio_in(BUTTON_B_PIN) == 0) add_angle -= 0.6; } else { static bool pressed; static bool flow; if (BUTTON_A_PIN >=0 && lgfx::gpio_in(BUTTON_A_PIN) == 0) { if (!pressed) { pressed = true; flow = !flow; } add_angle += flow ? 0.6 : -0.6; } else { pressed = false; } } } angle += add_angle; add_angle = add_angle * 9 / 10; rad = angle * - deg_to_rad; ax += sinf(rad) * gravity; ay -= cosf(rad) * gravity; ax = ax * 9.7 / 10; ay = ay * 9.7 / 10; float addy = (ay<0.0) ? -cr:cr; auto tmpy = roundf(cy+ay+addy); if ( 3 == sp.readPixelValue(roundf(cx), tmpy)) { cy = tmpy - addy + (ay < 0.0 ? 0.5 : -0.5); ay = -ay * 9.0 / 10; } else { cy += ay; } float addx = (ax<0.0) ? -cr:cr; auto tmpx = roundf(cx+ax+addx); if ( 3 == sp.readPixelValue(tmpx, roundf(cy))) { cx = tmpx - addx + (ax < 0.0 ? 0.5 : -0.5); ax = -ax * 9.0 / 10; } else { cx += ax; } std::uint32_t pv = sp.readPixelValue(roundf(cx), roundf(cy)); if ( 0 == pv) { sp.drawPixel(roundf(cx), roundf(cy), 2); } else if (1 == pv) return true; if (++skip_count == draw_cycle) { skip_count = 0; draw(); } return false; } void setup(void) { lgfx::lgfxPinMode(BUTTON_A_PIN, lgfx::pin_mode_t::input); lgfx::lgfxPinMode(BUTTON_B_PIN, lgfx::pin_mode_t::input); lcd.init(); lcd.startWrite(); lcd.setColorDepth(16); sp.setColorDepth(2); sp.createSprite(257, 257); game_init(); } void loop(void) { if (!game_main()) { lcd.fillCircle(px, py, roundf(cr*zoom), 0xFFFF00U); } else { std::int32_t py0 = lcd.height() >> 1; float cx0 = (cx + (sp.width() >>1)) / 2; float cy0 = (cy + (sp.height()>>1)) / 2; for (;;) { draw(); if (py < py0) ++py; if (cx != cx0) cx += (cx0 - cx) / 256; if (cy != cy0) cy += (cy0 - cy) / 256; angle += .5; rad = angle * - deg_to_rad; zoom *= 1 - zoom_speed; if (zoom < zoom_min) { std::int32_t tx, ty; zoom = zoom_min; if ((BUTTON_A_PIN >=0 && lgfx::gpio_in(BUTTON_A_PIN) == 0) || (BUTTON_B_PIN >=0 && lgfx::gpio_in(BUTTON_B_PIN) == 0) || lcd.getTouch(&tx, &ty) ) break; } } game_init(); } }