using UnityEngine; using UnityEngine.UI; using UnityEngine.InputSystem; using System.Collections.Generic; public class CodingModeGridManager : MonoBehaviour { [Header("スティック入力設定")] [Tooltip("移動に使用するコントローラーのスティックのInputActionPropertyを指定してください")] [SerializeField] private InputActionProperty thumbstickAction; [Range(0.1f, 0.9f)] [SerializeField] private float inputThreshold = 0.5f; // スティックをどれくらい倒したら動くか [Header("5x5 マス目(UI Image)の登録")] [Tooltip("ヒエラルキー上の25個のマス目のImageコンポーネントを、左上(0)から右下(24)の順番で格納してください")] [SerializeField] private List gridCells = new List(); [Header("マスの配色設定")] [SerializeField] private Color colorNormal = Color.gray; [SerializeField] private Color colorPlayer = Color.green; // 自機(プレイヤー) [SerializeField] private Color colorGoal = Color.yellow; // ゴール [SerializeField] private Color colorFailZone = Color.red; // 失敗ゾーン [SerializeField] private Color colorCheckpoint = Color.cyan; // チェックポイント // 内部で使用するマスの種類定義 private enum CellType { Normal, Start, Goal, FailZone, Checkpoint } private CellType[] cellLogicArray = new CellType[25]; private string[] checkpointBuffTypeArray = new string[25]; // 各チェックポイントに割り振るバフ名 // プレイヤーの現在位置(X:0~4, Y:0~4) private int playerX = 0; private int playerY = 0; // ゴールの位置 private int goalX = 4; private int goalY = 4; // スティックの連続移動を防ぐためのフラグ(一度スティックを中央に戻さないと連続で動かない仕様) private bool isStickNeutral = true; // 道中で踏んで現在蓄積されているバフのリスト private List accumulatedBuffs = new List(); private void OnEnable() { if (thumbstickAction.action != null) thumbstickAction.action.Enable(); } private void OnDisable() { if (thumbstickAction.action != null) thumbstickAction.action.Disable(); } private void Update() { // ─── ★Time.timeScale = 0 でも動くスティック入力移動ロジック ─── if (thumbstickAction.action == null) return; Vector2 stickInput = thumbstickAction.action.ReadValue(); // スティックが中央付近に戻ったらニュートラル状態を復帰 if (stickInput.magnitude < inputThreshold) { isStickNeutral = true; return; } // ニュートラル状態のときのみ、倒された方向に応じて1マスだけ移動させる if (isStickNeutral) { if (Mathf.Abs(stickInput.x) > Mathf.Abs(stickInput.y)) { // 横移動 if (stickInput.x > inputThreshold) MovePlayer(1, 0); // 右 else if (stickInput.x < -inputThreshold) MovePlayer(-1, 0); // 左 } else { // 縦移動 (UIの配列構造上、上に行くとYマイナス、下に行くとYプラスとなるよう計算) if (stickInput.y > inputThreshold) MovePlayer(0, -1); // 上 else if (stickInput.y < -inputThreshold) MovePlayer(0, 1); // 下 } } } /// /// 盤面を完全に初期化し、失敗ゾーンやチェックポイントをランダムに再配置する(PlayerStatusManagerから呼ばれる) /// public void ResetAndGenerateMinigame() { accumulatedBuffs.Clear(); // 1. 全マスを通常マスとして初期化 for (int i = 0; i < 25; i++) { cellLogicArray[i] = CellType.Normal; checkpointBuffTypeArray[i] = ""; } // 2. スタートとゴールの固定配置 (左上スタート、右下ゴール) playerX = 0; playerY = 0; goalX = 4; goalY = 4; cellLogicArray[GetIndex(0, 0)] = CellType.Start; cellLogicArray[GetIndex(4, 4)] = CellType.Goal; // 3. 失敗ゾーン(赤マス)をランダムに5個配置 (スタート・ゴールには被らせない) int failZonesPlaced = 0; while (failZonesPlaced < 5) { int randIndex = Random.Range(1, 24); // 0と24を避ける if (cellLogicArray[randIndex] == CellType.Normal) { cellLogicArray[randIndex] = CellType.FailZone; failZonesPlaced++; } } // 4. チェックポイント(青マス)を3つのバフに対応させてランダムに3個配置 string[] buffPool = { "AttackUp", "DefenseUp", "Heal" }; int checkpointsPlaced = 0; while (checkpointsPlaced < 3) { int randIndex = Random.Range(1, 24); if (cellLogicArray[randIndex] == CellType.Normal) { cellLogicArray[randIndex] = CellType.Checkpoint; checkpointBuffTypeArray[randIndex] = buffPool[checkpointsPlaced]; checkpointsPlaced++; } } // 5. 視覚的(UIの色)に反映 RedrawGridGraphic(); } /// /// プレイヤーの位置を指定された方向へ動かし、移動先のイベントを判定する /// private void MovePlayer(int xDirection, int yDirection) { int nextX = Mathf.Clamp(playerX + xDirection, 0, 4); int nextY = Mathf.Clamp(playerY + yDirection, 0, 4); // 壁にぶつかって座標が変わらなかった場合は移動不発とし、連続移動防止もかけない if (nextX == playerX && nextY == playerY) return; playerX = nextX; playerY = nextY; isStickNeutral = false; // 1回動いたのでロックをかける int currentIndex = GetIndex(playerX, playerY); CellType landedCell = cellLogicArray[currentIndex]; Debug.Log($"👾 カーソル移動: ({playerX}, {playerY}) | マス属性: {landedCell}"); // 移動先のマスに応じた処理 switch (landedCell) { case CellType.FailZone: PlayerStatusManager.Instance.FailCodingMode(); // 強制終了 return; case CellType.Checkpoint: string buff = checkpointBuffTypeArray[currentIndex]; if (!accumulatedBuffs.Contains(buff)) { accumulatedBuffs.Add(buff); Debug.Log($"💚 バフコード抽出成功: [{buff}] を一時キープ中!"); } break; case CellType.Goal: PlayerStatusManager.Instance.CompleteCodingMode(accumulatedBuffs); // クリア!バフ適用 return; } // 画面の色を最新状態に更新 RedrawGridGraphic(); } /// /// 現在のロジック配列に基づいて、25個のUI Imageの色をまとめて上書き変更する /// private void RedrawGridGraphic() { for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { int index = GetIndex(x, y); if (gridCells[index] == null) continue; // 基本の色を決定 switch (cellLogicArray[index]) { case CellType.Start: case CellType.Normal: gridCells[index].color = colorNormal; break; case CellType.FailZone: gridCells[index].color = colorFailZone; break; case CellType.Checkpoint: gridCells[index].color = colorCheckpoint; break; case CellType.Goal: gridCells[index].color = colorGoal; break; } // チェックポイントをすでに踏み抜いている場合は、獲得済みとして通常色に戻す演出(任意) if (cellLogicArray[index] == CellType.Checkpoint && accumulatedBuffs.Contains(checkpointBuffTypeArray[index])) { gridCells[index].color = colorNormal * 0.7f; // 少し暗いグレーにして区別 } } } // 最後にプレイヤーのいるマスを「自機の色」で最優先に塗り替える int playerIndex = GetIndex(playerX, playerY); if (gridCells[playerIndex] != null) { gridCells[playerIndex].color = colorPlayer; } } // 2次元座標 (X, Y) から 1次元の配列添字 (0~24) を割り出すヘルパーメソッド private int GetIndex(int x, int y) { return y * 5 + x; } }