279 lines
6.4 KiB
C++
279 lines
6.4 KiB
C++
#include <LovyanGFX.hpp>
|
|
|
|
|
|
#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();
|
|
}
|
|
}
|