diff --git a/reel_left b/reel_left new file mode 100644 index 0000000..9354013 --- /dev/null +++ b/reel_left @@ -0,0 +1,198 @@ +//左リール +#include +#include +#include + +// ========================================================================= +// 1. 画像データ(幅135px × 高さ1680px、16bit RGB565) +// ========================================================================= +const uint16_t reel_image_data[226800] PROGMEM = { + + //----------------------カラーコードの塊のため省略---------------------- + +}; +// ========================================================================= +// 2. ソフトウェア制御用の設定 +// ========================================================================= + +// --- 図柄の定義 --- +enum SymbolType { + GRAPE = 0, // ブドウ + SEVEN = 1, // 赤7 + BAR = 2, // BAR + BELL = 3, // ベル + RHINO = 4, // ツノッチ(サイ) + CLOWN = 5, // ピエロ + CHERRY= 6 // チェリー + }; + +const int TOTAL_SYMBOLS = 21; // 総図柄数 +const int MY_REEL_ID = 0; +// --- リールの配列 --- +const SymbolType reel_array[TOTAL_SYMBOLS] = { + RHINO, SEVEN, GRAPE, CHERRY, RHINO, BELL, GRAPE, CHERRY, RHINO, BAR, GRAPE, + CHERRY, RHINO, BELL, GRAPE, CHERRY, RHINO, BAR, GRAPE, CHERRY, CLOWN + }; + +// --- 内部フラグ(成立役)の定義 --- +enum InternalFlag { + FLAG_BLANK = 0, // ハズレ + FLAG_REPLAY = 1, // リプレイ + FLAG_GRAPE = 2, // ブドウ + FLAG_CHERRY = 3, // チェリー + FLAG_BELL = 4, // ベル + FLAG_CLOWN = 5, // ピエロ + FLAG_BIG = 6, // BIG + FLAG_REG = 7 // REG + }; + +InternalFlag current_flag = FLAG_BLANK; // 現在の内部状態 + +// --- 左リール 第一停止用の制御表(下段基準) --- +// [注]引数0~20→図柄番号21~1 +const int slip_tables[8][21] = { + // [0] FLAG_BLANK (ハズレ) + {2, 0, 1, 2, 2, 4, 3, 1, 2, 3, 4, 0, 1, 2, 2, 3, 3, 4, 3, 0, 1}, + // [1] FLAG_REPLAY (リプレイ) + {2, 2, 0, 1, 0, 1, 0, 2, 4, 4, 0, 1, 1, 3, 4, 4, 2, 2, 4, 0, 1}, + // [2] FLAG_GRAPE (ブドウ) + {2, 1, 1, 2, 0, 1, 0, 2, 4, 4, 0, 1, 2, 0, 0, 0, 2, 4, 4, 0, 1}, + // [3] FLAG_CHERRY (チェリー) + {3, 4, 0, 4, 0, 4, 0, 0, 1, 2, 1, 4, 3, 4, 0, 0, 0, 1, 2, 1, 4}, + // [4] FLAG_BELL (ベル) + {0, 1, 2, 2, 4, 4, 4, 2, 4, 4, 0, 1, 2, 1, 0, 0, 2, 4, 4, 0, 1}, + // [5] FLAG_CLOWN (ピエロ) + {2, 1, 0, 4, 0, 4, 0, 2, 4, 4, 0, 1, 0, 1, 2, 3, 3, 3, 4, 0, 1}, + // [6] FLAG_BIG (BIGボーナス) + {2, 0, 1, 2, 2, 4, 4, 4, 2, 3, 4, 0, 1, 2, 2, 3, 3, 4, 3, 0, 1}, + // [7] FLAG_REG (REGボーナス) + {2, 0, 1, 2, 2, 4, 4, 4, 2, 3, 4, 0, 1, 2, 2, 3, 3, 4, 3, 0, 1} +}; + +// ========================================================================= +// 通信設定 +// ========================================================================= +// メイン機から受け取る「命令とテーブル」 +typedef struct struct_main_to_reel { + int command; + int slip_table[21]; // メイン機が計算した21コマ分の滑り表 +} struct_main_to_reel; +struct_main_to_reel receiveData; + +// メイン機へ報告する「停止位置」 +typedef struct struct_reel_to_main { + int reel_id = 0; + int stopped_index; +} struct_reel_to_main; +struct_reel_to_main reportData; + +// 一斉送信(ブロードキャストアドレス) +uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +esp_now_peer_info_t peerInfo; + +enum ReelState { STOPPED, SPINNING, SLIPPING }; +ReelState reel_state = STOPPED; + +// --- メイン機からデータを受け取った時の処理 --- +void OnDataRecv(const esp_now_recv_info *info, const uint8_t *incomingData, int len) { + // データの重さがメイン機からの「命令+テーブル」と一致した場合のみ処理 + if (len == sizeof(struct_main_to_reel)) { + struct_main_to_reel temp; + memcpy(&temp, incomingData, sizeof(temp)); + + // commandが 99(全員一斉回転) か、自分のID(0〜2)宛ての専用テーブルの時のみ + if (temp.command == 99 || temp.command == MY_REEL_ID) { + memcpy(&receiveData, &temp, sizeof(receiveData)); + + if (temp.command == 99 && reel_state == STOPPED) { + reel_state = SPINNING; + Serial.println(">> 全リール一斉回転スタート!"); + } else if (temp.command == MY_REEL_ID) { + Serial.println(">> AIから最新の滑りテーブルを受信・更新しました"); + } + } + } +} + +// ========================================================================= +// ハードウェア設定 +// ========================================================================= +const int SYMBOL_W = 135; const int SYMBOL_H = 80; +const int REEL_H = 1680; const int WINDOW_H = 240; +M5Canvas canvas(&M5.Display); + +int current_y = 0; int target_y = 0; int bita_y = 0; int scroll_speed = 60; + +void setup() { + auto cfg = M5.config(); M5.begin(cfg); Serial.begin(115200); + M5.Display.setRotation(0); M5.Display.fillScreen(TFT_BLACK); + canvas.createSprite(SYMBOL_W, WINDOW_H); canvas.setSwapBytes(true); + + WiFi.mode(WIFI_STA); + if (esp_now_init() != ESP_OK) return; + + // 受信設定 + esp_now_register_recv_cb(OnDataRecv); + + // 送信設定 + memcpy(peerInfo.peer_addr, broadcastAddress, 6); + peerInfo.channel = 0; peerInfo.encrypt = false; + esp_now_add_peer(&peerInfo); +} + +void loop() { + M5.update(); + + // --- Aボタン(ストップボタン) --- + if (M5.BtnA.wasPressed()) { + if (reel_state == SPINNING) { + reel_state = SLIPPING; + bita_y = (current_y / SYMBOL_H) * SYMBOL_H; + int bita_top_index = bita_y / SYMBOL_H; + int bita_btm_index = (bita_top_index + 2) % TOTAL_SYMBOLS; + + int slip_frames = receiveData.slip_table[bita_btm_index]; + + target_y = bita_y - (slip_frames * SYMBOL_H); + if (target_y < 0) target_y += REEL_H; + } + } + + // --- 回転・滑り処理 --- + if (reel_state == SPINNING) { + current_y -= scroll_speed; + if (current_y < 0) current_y += REEL_H; + } + else if (reel_state == SLIPPING) { + int distance = current_y - target_y; + if (distance < 0) distance += REEL_H; + + if (distance <= scroll_speed) { + current_y = target_y; + reel_state = STOPPED; + + int top_index = current_y / SYMBOL_H; + int btm_index = (top_index + 2) % TOTAL_SYMBOLS; + + reportData.reel_id = 0; + reportData.stopped_index = btm_index; + esp_now_send(broadcastAddress, (uint8_t *) &reportData, sizeof(reportData)); + + Serial.printf("【完了】下段インデックス %d で停止。メイン機へ報告しました。\n", btm_index); + } else { + current_y -= scroll_speed; + if (current_y < 0) current_y += REEL_H; + } + } + + // --- 描画処理 --- + if (current_y + WINDOW_H <= REEL_H) { + canvas.pushImage(0, 0, SYMBOL_W, WINDOW_H, (uint16_t*)reel_image_data + (current_y * SYMBOL_W)); + } else { + int first_part_h = REEL_H - current_y; + int second_part_h = WINDOW_H - first_part_h; + canvas.pushImage(0, 0, SYMBOL_W, first_part_h, (uint16_t*)reel_image_data + (current_y * SYMBOL_W)); + canvas.pushImage(0, first_part_h, SYMBOL_W, second_part_h, (uint16_t*)reel_image_data); + } + canvas.pushSprite(0, 0); delay(5); +}