/* プレイエリアのセルの処理とか * 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++; } } }
/// <summary>プレイエリアを1フレーム分更新する</summary> /// <param name="userOperation">ユーザーの操作</param> public void InputKey(UserOperation userOperation) { // 更新時の最初の処理 フレーム1増加 ElapseFrame++; /* ゲームアップデートの順序 * 1. ユーザーの操作 * * カーソル位置移動 * * セルの入れ替え * 2. スクロール * * IF ちょうど1段上がったなら、 * * セルを全て1段上に上げる * * Row:-1 の段にセルを生成する * * カーソルの位置を1段上に上げる * 3. セルの状態の更新 * 1. 全てのセルの状態を更新する * * StateTimer のカウントを減らす * 2. セルの落下 * 3. 消滅するセルの検査 * 1. 消滅するセルは、StateTiemr をセットする * 2. お邪魔とかいろいろ… */ // ユーザーの操作 _cursorStatus = CursorStatus.Update(userOperation); // スクロール ScrollLine += 2; // スクロールする if (PushedUp = ScrollLine >= BorderLine) // ちょうど1段スクロールした { ScrollLine = 0; // スクロールラインを戻す s++; // 全てのセルを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段上げる // カーソルを1段上に上げる var cr = CursorStatus; var mr = cr.Matrix; mr.Row++; // ホントはここがしたいだけ cr.Matrix = mr; _cursorStatus = cr; } ScrollPer = ScrollLine / BorderLine; // 現在のスクロール割合 _swapArray[s, 0] = null; _swapArray[s, 1] = null; // セルの状態更新 if (B) // 左から右 { _cellArray[s, 0] = _cellArray[s, 0].Update(); if (_cellArray[s, 0].StateTimer.Lock == 0) { var cell = _cellArray[s, 0]; cell.StateTimer = (0, 0, 10); cell.Status = CellState.Lock; _cellArray[s, 1] = cell; _swapArray[s, 0] = new(s, 1); B = false; } } else // 右から左 { _cellArray[s, 1] = _cellArray[s, 1].Update(); if (_cellArray[s, 1].StateTimer.Lock == 0) { var cell = _cellArray[s, 1]; cell.StateTimer = (0, 0, 10); cell.Status = CellState.Lock; _cellArray[s, 0] = cell; _swapArray[s, 1] = new(s, 0); B = true; } } // 最後に、更新したよ~って言う Updated(this, EventArgs.Empty); }