using UnityEngine; using UnityEngine.UI; using UnityEngine.InputSystem; using System.Collections.Generic; public class CodingModeGridManager : MonoBehaviour { [SerializeField] private InputActionProperty thumbstickAction; [SerializeField] private float inputThreshold = 0.5f; // スティックをどれくらい倒したら動くか [SerializeField] private List gridCells = new List(); [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() { 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 { if (stickInput.y > inputThreshold) MovePlayer(0, -1); else if (stickInput.y < -inputThreshold) MovePlayer(0, 1); } } } /// 盤面を初期化し、ランダムに再配置する(PlayerStatusManagerから呼ばれる) public void ResetAndGenerateMinigame() { accumulatedBuffs.Clear(); // 全マスを通常マスとして初期化 for (int i = 0; i < 25; i++) { cellLogicArray[i] = CellType.Normal; checkpointBuffTypeArray[i] = ""; } // スタートとゴールの固定配置、(余裕があればランダムに) playerX = 0; playerY = 0; goalX = 4; goalY = 4; cellLogicArray[GetIndex(0, 0)] = CellType.Start; cellLogicArray[GetIndex(4, 4)] = CellType.Goal; // 失敗ゾーンをランダムに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++; } } // チェックポイントを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++; } } 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; } }