Last active
May 23, 2025 17:40
-
-
Save Yuikawa-Akira/1cb6fcb367ee46bd4ef842d55f3c83eb to your computer and use it in GitHub Desktop.
Random-Particle-Snow-for-Tab5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <M5Unified.h> // 0.2.7 以降 | |
// --- パラメータ設定 --- | |
const int dotScale = 16; // 2の倍数 | |
const int CANVAS_WIDTH = 1280 / dotScale; | |
const int CANVAS_HEIGHT = 720 / dotScale; | |
// ドット落下速度 | |
const int FALL_SPEED_MS = 10; | |
// 新しいドットが出現する間隔 | |
const int NEW_DOT_INTERVAL_MS = 10; | |
// 同時に落下できるドットの最大数 | |
const int MAX_FALLING_DOTS = CANVAS_HEIGHT * FALL_SPEED_MS / NEW_DOT_INTERVAL_MS; | |
// グリッド上に固定されたドットの数 | |
int fixedDotCount = 0; | |
// グリッドの状態を保持する2D配列 (0: 空, 1: ドットあり) | |
uint8_t grid[CANVAS_WIDTH][CANVAS_HEIGHT]; | |
// 落下中のドットを表す構造体 | |
struct FallingDot { | |
int x; | |
int y; | |
int r; | |
int g; | |
int b; | |
bool active; // 落下中かどうか | |
}; | |
FallingDot fallingDots[MAX_FALLING_DOTS]; | |
// タイマー用変数 | |
unsigned long lastNewDotTime = 0; | |
unsigned long lastFallTime = 0; | |
// グリッドを初期化する関数 | |
void initializeGrid() { | |
memset(grid, 0, sizeof(grid)); | |
} | |
// 落下中のドットを初期化する関数 | |
void initializeFallingDots() { | |
for (int i = 0; i < MAX_FALLING_DOTS; ++i) { | |
fallingDots[i].active = false; | |
} | |
} | |
void setup() { | |
auto cfg = M5.config(); | |
M5.begin(cfg); | |
M5.Display.fillScreen(TFT_WHITE); | |
initializeGrid(); | |
initializeFallingDots(); | |
M5.delay(500); | |
// 最初の描画 | |
M5.Display.fillScreen(TFT_BLACK); // 背景を黒でクリア | |
} | |
void loop() { | |
unsigned long currentTime = millis(); | |
// 新しいドットの出現を試みる | |
if (currentTime - lastNewDotTime > NEW_DOT_INTERVAL_MS) { | |
lastNewDotTime = currentTime; | |
// 空いている落下中のドットスロットを探す | |
int freeSlot = -1; | |
for (int i = 0; i < MAX_FALLING_DOTS; ++i) { | |
if (!fallingDots[i].active) { | |
freeSlot = i; | |
break; | |
} | |
} | |
if (freeSlot != -1) { | |
int newX = random(CANVAS_WIDTH); // x座標はランダム | |
int newY = 0; // 最上段に出現 | |
// 出現位置にドットが存在しないかチェック | |
if (grid[newX][newY] == 0) { | |
fallingDots[freeSlot].x = newX; | |
fallingDots[freeSlot].y = newY; | |
fallingDots[freeSlot].r = random(2, 15) * 16; | |
fallingDots[freeSlot].g = random(2, 15) * 16; | |
fallingDots[freeSlot].b = random(2, 15) * 16; | |
fallingDots[freeSlot].active = true; | |
} | |
} | |
} | |
// ドットの落下処理 | |
if (currentTime - lastFallTime > FALL_SPEED_MS) { | |
lastFallTime = currentTime; | |
for (int i = 0; i < MAX_FALLING_DOTS; ++i) { | |
if (fallingDots[i].active) { | |
M5.Display.fillRect((fallingDots[i].y - 1) * dotScale, fallingDots[i].x * dotScale, dotScale, dotScale, TFT_BLACK); // 1個上を消す | |
M5.Display.fillRect(fallingDots[i].y * dotScale, fallingDots[i].x * dotScale, dotScale, dotScale, M5.Display.color565(fallingDots[i].r, fallingDots[i].g, fallingDots[i].b)); | |
int currentX = fallingDots[i].x; | |
int currentY = fallingDots[i].y; | |
int nextY = currentY + 1; | |
// 落下可能かチェック (最下段に達していない & 下にドットがない) | |
if (nextY < CANVAS_HEIGHT && grid[currentX][nextY] == 0) { | |
// 落下中のドットの座標を更新 | |
fallingDots[i].y = nextY; | |
} else { | |
// 落下終了 | |
grid[currentX][currentY] = 1; // グリッドにドットを配置 | |
M5.Display.fillRect(currentY * dotScale, currentX * dotScale, dotScale, dotScale, M5.Display.color565(fallingDots[i].r, fallingDots[i].g, fallingDots[i].b)); | |
fallingDots[i].active = false; // 落下を停止 | |
fixedDotCount++; // ここでカウントを増やす | |
} | |
} | |
} | |
} | |
M5.delay(1); | |
// 全てのグリッドが埋まったらリセット | |
if (fixedDotCount >= (CANVAS_WIDTH * CANVAS_HEIGHT)) { | |
initializeGrid(); | |
initializeFallingDots(); | |
fixedDotCount = 0; // カウントをリセット | |
M5.Display.fillScreen(TFT_BLACK); // 画面をクリア | |
M5.delay(1000); // 1秒待機 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment