public PlayArea(int row, int col) { this.PlayAreaSize = new Matrix(row, col); // セルの存在する2次元配列 // rows(縦列)はお邪魔が降って来て画面上範囲外にセルが存在するので、1.5倍にして、 // 一番下はせり上がる列なので更に+1 this._cellArray = new RectangleArray <CellInfo>((int)(row * 1.5) + 1, col); this._swapArray = new RectangleArray <Matrix?>(CellArray.Row, CellArray.Column); // カーソルは最上段に行けない this.CursorStatus = new CursorStatus(PlayAreaSize.Row - 1, PlayAreaSize.Column - 1); PlayAreaInit(); }
public TestPlayAreaServie() { // 固定値 this._playAreaSize = new Matrix(12, 6); this.BorderLine = 100; // 更新ごとに変動 簡単な値の変化 this.ElapseFrame = 0; this.ScrollLine = 0; this.ScrollPer = 0; // 更新ごとに変動 大事な値 this._cellArray = new RectangleArray <CellInfo>(18, 6); this._cursorStatus = new CursorStatus(PlayAreaSize.Row, PlayAreaSize.Column - 1); _cursorStatus.Matrix.Row = 0; _cursorStatus.Matrix.Column = 0; this._swapArray = new RectangleArray <Matrix?>(CellArray.Matrix); // セルの初期化 _cellArray[0, 0] = RedCell; }
/// <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; // スクロール速度の初期化 // せり上がっている今の高さの初期化 // (まだフィールドすら無いけど)お邪魔の初期化 }
/// <summary> /// 繋がっているかを検査する /// </summary> /// <param name="res">結果</param> /// <param name="func">Row,Columnの値を増やすデリゲート</param> /// <param name="beforeType">1つ前に検査したセルの種類</param> /// <param name="chain">1つ前の連鎖数</param> /// <param name="now">今回調べる位置</param> /// <returns>3つ以上の繋がっているうちの1つだった</returns> bool Serch(ref RectangleArray <bool> res, Func <Matrix, Matrix> func, CellInfo beforeCell, int chain, Matrix now) { // 今回調べるセル var nowCell = CellArray[now]; // 前回のセル or 今回のセルが消滅に使えない または 今回調べるセルと違うタイプ or if (!beforeCell.IsEliminatable || !nowCell.IsEliminatable || nowCell.CellType != beforeCell.CellType) { chain = 1; } else { chain++; } var next = func(now); var isChain = false; if (next.Row < res.Row && next.Column < res.Column) { isChain = Serch(ref res, func, nowCell, chain, next); } else if (chain >= 3) { isChain = true; // return res[now] = true; 確定 } if (isChain || chain >= 3) { res[now] = isChain = true; } else { res[now] = res[now] || false; } return(chain > 1 && isChain); }
/* プレイエリアのセルの処理とか * 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++; } } }