/// <summary> /// <para>プレイエリアの状態を初期化する</para> /// </summary> private void PlayAreaInit() { // カーソル位置を初期化 var cursor = CursorStatus; cursor.Matrix.Row = 0; cursor.Matrix.Column = 0; CursorStatus = cursor; // セルの配置を初期化する _cellArray = CellArray.CopyAndReset(CellInfo.Empty); for (int row = -1; row <= 5; row++) { for (int col = 0; col < PlayAreaSize.Column; col++) { var cell = CellArray[row, col]; cell.CellType = CellInfo.RandomCellType(n: -1); _cellArray[row, col] = cell; } } //==============================Debug用 //// 一番下(Row-1)のセルをランダムに追加する //for(int col = 0; col < PlayAreaSize.Column; col++) { // var cell = CellArray[-1, col]; // cell.CellType = CellInfo.RandomCellType(n: 0); // _cellArray[-1, col] = cell; //} //==============================Debug用 ここまで //var ojama = new CellInfo { // CellType = CellType.Ojama, //}; // スクロール位置の初期化 ScrollLine = 0; // スクロール速度の初期化 // せり上がっている今の高さの初期化 // (まだフィールドすら無いけど)お邪魔の初期化 }
/* プレイエリアのセルの処理とか * 1.ユーザーの操作 * 2.スクロールする(しないときもある) * ここでせり上がる時に一番上にセルがあればゲームオーバー * 3.左下から、右に、上に向かって、セルの状態変化(移動/変化) * 4.お邪魔セルの落下 */ /// <summary> /// ゲームの状態を1フレーム更新する /// </summary> /// <param name="userOperation">ユーザーの操作</param> private void GameRule(UserOperation userOperation) { // 移動したセル配列の初期化 _swapArray = SwapArray.CopyAndReset(null); //==============================スクロールする============================== // ScrollLine が BorderLine を超えているか?(1段上に上げるか?) PushedUp = ScrollLine >= BorderLine; // スクロール待機中なら、待機フレーム数を1減らしてスクロールしない if (_scrollWaitFrame > 0) { _scrollWaitFrame--; } else { // ゲームオーバーか? if (GameOverJudge()) { return; } // スクロールする ScrollLine += ScrollSpeed; if (PushedUp) { ScrollLine = 0; // セルを1段上に上げる for (var row = PlayAreaSize.Row - 2; row >= -1; row--) { for (var col = 0; col < PlayAreaSize.Column; col++) { _cellArray[row + 1, col] = CellArray[row, col]; } } // カーソルを1段上に上げる var cr = CursorStatus; var mr = cr.Matrix; mr.Row++; // ホントはここがしたいだけ cr.Matrix = mr; CursorStatus = cr; // 一番下(Row-1)のセルをランダムに追加する for (int col = 0; col < PlayAreaSize.Column; col++) { var cell = CellArray[-1, col]; cell.CellType = CellInfo.RandomCellType(n: 0); _cellArray[-1, col] = cell; } } } //==============================ユーザーの操作============================== switch (userOperation) { case UserOperation.Swap: // カーソルの位置のセルを入れ替える // カーソルの位置のセルを取得 var cursorCellL = CellArray[CursorStatus.Matrix.Row, CursorStatus.Matrix.Column]; var cursorCellR = CellArray[CursorStatus.Matrix.Row, CursorStatus.Matrix.Column + 1]; // 両方Emptyなら入れ替える必要がないので入れ替えない if (cursorCellL.CellType is CellType.Empty && cursorCellR.CellType is CellType.Empty) { break; } // カーソル位置のセルのどちらも移動可能(両方空なら上で弾かれる) if (!cursorCellL.CellType.IsOjama() && cursorCellL.Status is CellState.Free && !cursorCellR.CellType.IsOjama() && cursorCellR.Status is CellState.Free) { SwapCell(CursorStatus.Matrix.Row, CursorStatus.Matrix.Column, CursorStatus.Matrix.Row, CursorStatus.Matrix.Column + 1); } break; case UserOperation.ScrollSpeedUp: // TODO: スクロール速度が上昇する break; default: break; } // カーソルの状態を更新する CursorStatus = CursorStatus.Update(userOperation); //==============================セルの状態を更新する============================== /* ・更新順序 * 1. セルの状態更新 * 2. 今回のフレームで入れ替わる * (入れ替え or 落下。入れ替わったセルは SwapArray の対応した場所にインデックスが入る) * 3. セルの消滅、変身 * * 消滅セルを検査する * * 変身するお邪魔セルを検査する * * 消滅、変身するセルの状態をセットする */ //======================セルの状態更新 //========全てのセルを更新 for (int row = 0; row < CellArray.Row; row++) { for (int col = 0; col < CellArray.Column; col++) { var cell = CellArray[row, col]; cell.Update(); _cellArray[row, col] = cell; } } //==========セルの落下 for (int row = 1; row < CellArray.Row; row++) { for (int col = 0; col < CellArray.Column; col++) { // TODO: お邪魔の落下 // 自分のセルが Not(種類:ノーマル or 状態:Free) if (!CellArray[row, col].CellType.IsNomal() || CellArray[row, col].Status is not CellState.Free) { continue; } var bottomCell = CellArray[row - 1, col]; // 下のセルが 種類:空 かつ 状態:Free if (bottomCell.CellType is CellType.Empty && bottomCell.Status is CellState.Free) { // 自分と下のセルを入れ替えて、落下を起こす SwapCell(row, col, row - 1, col, isSwap: false); } } } //==========================セルの消滅、変身 var listD = new List <(int row, int col, CellInfo)>(); // お邪魔。変身するセルを格納する var searchAry = new RectangleArray <bool>(PlayAreaSize); // 横列走査 var funcRow = new Func <Matrix, Matrix>(m => { m.Column++; return(m); }); for (int row = 0; row < searchAry.Row; row++) { Serch(res: ref searchAry, func: funcRow, beforeCell: CellInfo.Empty, chain: 0, new Matrix(row, 0)); } // 縦列走査 var funcCol = new Func <Matrix, Matrix>(m => { m.Row++; return(m); }); for (int col = 0; col < searchAry.Column; col++) { Serch(res: ref searchAry, func: funcCol, beforeCell: CellInfo.Empty, chain: 0, new Matrix(0, col)); } // TODO: 変身するお邪魔セル走査 //// 重複を取り除いて、row の降順 col の昇順に並び替え //listC = listC.Distinct().OrderByDescending(c => c.row).ThenBy(c => c.col).ToList(); // 消滅するセルを、消滅するように仕向ける int cnt = 0; // 消滅セル数 (左上から順番にカウント) int sum = searchAry.Count(b => b); // 消滅セル数合計 for (int row = searchAry.Row - 1; row >= 0; row--) { for (int col = 0; col < searchAry.Column; col++) { if (!searchAry[row, col]) { continue; } var cell = CellArray[row, col]; // 状態遷移タイマーのセット cell.StateTimer = (flashTime, cnt *momentTime + 2, (sum - cnt) * momentTime); // セルの状態をフラッシュに cell.Status = CellState.Flash; _cellArray[row, col] = cell; cnt++; } } }