バグとか出そうな気もするのですが…
ま、完成したと言うことにします。
(;^o^) \(ToT )あんたほんとにそれでいいの
いよいよ大詰めのゲームオーバーの処理を作って行こうと思います。
2048のゲームオーバーは
・全マスが埋まる
・ピースが動けない状態
この二つを判定する必要があるかと思います。
さて、どのタイミングで判定をするかが問題かと…
ピース移動の度に呼び出すと重くなりそうですし、
ピース生成の度に呼び出すのもちょっと…
少しフローもどきを見て流れを考えます

全ての流れはSelectPosition()で終了を迎えます。
更にこのメソッド
//空きマスからランダムに2カ所を選ぶ
public void SelectPosition()
{
List<int> list = new List<int>();
int num = 2;
int rot = 0;
for(int i = 0; i < 16; i++)
{
if (Flag[i] == false)
{
list.Add(i);
}
}
if (list.Count == 1)
{
num = 1;
}
while (rot < num)
{
int pos = list.GetAndRemoveAtRandom();
int x = pos % frame;
int y = pos / frame;
CreatePiece(x, y, 0);
rot++;
}
create = false;
}
おあつらえ向きにマスの埋まり具合をリスト化しています。
これは使えそうです。
呼び出し部分は、ココで問題なさそうなので、
ピースの移動判定を考えてみます。
ピースは全ピース隣接するピースが同じかを判断する必要があるので、
//ピースの移動が出来るか判定する
void EndJudge()
{
for(int i = 0; i < 4; i++)
{
for(int a = 0; a < 4; a++)
{
SetNum[i, a]
}
}
}
こんな感じのループになります。
見るからに重そうです(;^_^A アセアセ・・・
SetNum[0,0]から順番にピースナンバーを取り出して、
次のピースと比較、取り出して比較…
こんな感じの繰り返しなんですが、これってどこかで見たような…
そうです!移動マス計算の時の処理に似ています。
流用できそうなので処理を作ってみます。
private const int hydepiece = 0; //判定用の隠しピース
//ピースの移動が出来るか判定する
void EndJudge()
{
//ピースナンバー仮取得する変数XY
int tempX=0;
int tempY=0;
for(int i = 0; i < 4; i++)
{
for(int a = 0; a < 4; a++)
{
//横軸の隣接ピースを確認する
if (SetNum[i, a] == tempX)
{
return;
}
else if (SetNum[i, a] == MAX_No)
{
tempX = hydepiece;
}
else
{
tempX = SetNum[i, a];
}
//縦軸の隣接ピースを確認する
if (SetNum[a, i] == tempY)
{
return;
}
else if (SetNum[a, i] == MAX_No)
{
tempY = hydepiece;
}
else
{
tempY = SetNum[a, i];
}
}
tempX = 0;
tempY = 0;
}
//ゲームオーバーなら呼び出す
メソッドや処理を書く
}
説明すると、
最初のループfor(int i = 0; i < 4; i++)で縦・横を数値化しています。
次のループfor(int a = 0; a < 4; a++)で列を数値化しています。
移動マス計算でも説明した、隣接ピースとの比較方法ですが、
ピースナンバー取り出し、仮変数に代入してループさせてます。
最後の方に変なtempX = 0; tempY = 0;を代入していますが、
これは、列の替わり目です。
for(int a = 0; a < 4; a++)で列の端まで行ったら、次の列に移動します。
その時にピースナンバーを持ち越すとおかしな事になるので、
リセットしています。
隣接してるピースが同じならループをreturnで抜けるようにしました。
これで少しは軽くなるかと思います。
ループが回り切ると隣接ピースも無い事が分かるので、
ゲームオーバーの処理となります。
移動マス計算でも導入しましたが、Maxピースナンバーを設定しているので、
Maxピースが並んで同じと判断されるとマズイので、hydepieceを用意しました。
これで、ピースが移動できるか判断できるので、
呼び出し側のSelectPosition()メソッドを修正します。
//空きマスからランダムに2カ所を選ぶ
public void SelectPosition()
{
List<int> list = new List<int>(); //空きマスを取得する変数
int num = 2; //ピースの生成回数
int rot = 0; //ピースの生成カウント
int limit=0; //空マスのカウント
for(int i = 0; i < 16; i++)
{
if (Flag[i] == false)
{
list.Add(i);
limit++;
}
}
//空きマスが一つならnumを修正する
if (list.Count == 1)
{
num = list.Count;
}
//ピースをnum回生成する
while (rot < num)
{
int pos = list.GetAndRemoveAtRandom();
int x = pos % frame;
int y = pos / frame;
CreatePiece(x, y, 0);
rot++;
}
//空マスが2つ以下なら移動できるか判定する
if (limit<=2)
{
ここで呼び出したいのだけれど…
}
create = false;
}
処理が増えて分かりにくくなったので、
コメントを入れてみました。
まず、変数limitを追加します。
ポジションから空きマスをリスト化している部分があるので、
空きマスの数をlimitにカウントします。
ここで注意なんですが、list.Countを使えばlimitでカウントする必要が
ないように思いますが、次の処理while (rot < num)で、
list.GetAndRemoveAtRandom();拡張メソッドを使っています。
これは、作成者の説明によると
ランダムに選択したリストの値を取得後、削除する。
との事です。
if (limit<=2)の部分をif (list.Count<=2)としたいのですが、
ピースの生成で削除されてるので、空きマスの数が変わって
しまいバグが出ます。
なので、while (rot < num)前でカウント出来る部分にlimitを仕込みました。
全マス埋まる状態は、空きマスが2つ以下の時なので、
limitが2つ以下ならEndJudge()メソッドを呼び出せば、
かなり負担も減らせそうでっす。(^ё^) ♪♪
と言う事でif (limit<=2)でEndJudge()メソッドを呼び出したいのですが…
実は、問題があります。
ピースは生成された時にポジション登録をするようになっています。
なので、生成後すぐに判定に移るとポジションが空になっている場合が…
流れですが、
ピースの生成呼び出し:while (rot < num)
↓ ↓
移動判定呼び出し:EndJudge() ピースの生成CreatePiece()
↓ ↓
移動可能かの判定 ピースの初期ポジション登録
かなり処理が並んでいます。
実際はピースの生成後にポジション登録されるので、
もしかすると移動判定より後に登録になる可能性もあります。
なので、ピースの生成を待つ為にウェイトを掛けて処理します。
//ピース生成まで待機して移動判定を呼び出す
IEnumerator waitJudge()
{
yield return new WaitForSeconds(0.2f);
EndJudge();
yield break;
}
計ってないのでハッキリした事は言えないのですが、
ピースの生成呼び出しから生成までが0.03秒前後、
ピース側からポジション登録されるまでが0.02秒前後、
2ピースでバラつきがあるとすれば0.1秒あれば十分対応できそうです。
ただ、少し余力を持たせて0.2秒のウェイトを掛ける事にします。
あとは
//空マスが2つ以下なら移動できるか判定する
if (limit<=2)
{
StartCoroutine("waitJudge");
}
コルーチンを呼び出せば完成でっす。
ゲームオーバーの処理を作って、
ついでにリスタートと終了ボタンを用意して…
PLAYしてみます。
再生できない場合、ダウンロードは🎥こちらMaxピースを2にしてPLAYしています。
無事に移動の判断ができております。
ゲームオーバーの処理が酷いのはスルーしてね(* v v)。ハズカシイ
これでビルドしてもスマホでも操作できるかと思います。
最後におまけなんですが、
リスタートとゲーム終了の処理を少々載せておきます。
//ゲームをリロードする
public void PushReStart()
{
for(int i = 0; i < 4; i++)
{
for(int a = 0; a < 4; a++)
{
SetNum[i, a] = 0;
}
}
create = false;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
//ゲームを終了する
public void PushGameEnd()
{
Application.Quit();
}
スマホでゲーム終了はコマンドを呼び出せばいいだけなのですが、
リスタートについては、少々注意点があります。
staticに設定しているSetNum[ , ]は、Sceneを変えてもリロードしても
残り続けると言う事です。
リスタートを導入される場合は、初期化する必要があります。
それとcreateはfalseに戻るようになっていますが、念の為初期化しとくと安心でっす。
なんとかPLAYできる所まで持ってこれました。
正直、ピースの移動処理を考えてる時は完成できないと思っていました。
考えればなんとかなるものですね~(^○^)v ワーイ
次はスマホでの実地になるかと思います。
あ!その前に得点の表示を忘れてました(;^_^A
ま、適当にこの辺を次回で処理していきたいと思います。
今日はこの辺で(^^)/~~デハデハ
×
この広告は90日以上新しい記事の投稿がないブログに表示されております。
この記事へのコメント