テトリスのブロックユニットの作成と配置方法について

VRゲームの作り方

今回はいよいよテトリスらしいブロックを作成していきます。

これまでは、ただの四角いキューブでしたが、テトリスブロックは長いものや、四角いもの、凸の形状のものなどがあります。

それぞれのブロックをユニット単位として生成し、シューティングテトリスのゲームロジックに組み込んでいきます。

【準備】Block.csの作成

まず、各ブロックがフィールド上のどこにあるかを記憶させるため、Block.csを作成しましょう。

中身は次のように記述してください。

ここで使用する個所は、int型のx,yのみです。例えば、block[5,12]の位置にあるブロックはx=5, y=12が格納されるようになります。

そして、プレハブのBlockにBlock.csをAddComponentしてください。

ブロックユニットの作成

まずは、ブロックの種類を決めるためのブロックタイプを作成していきます。

ブロックタイプの定義

BlockBazooka.csのBlockBazookaクラスの手前にBlockTypeという名前の構造体を作成してください。

この構造体の中に定義されたshapeは、int型の二次元配列で定義され、要素の中身が0の部分にはブロックがない状態を、1の部分にはブロックがある状態を示すようにします。

では、それに併せてBlockBazookaクラス内も修正していきます。BlockTypeの配列であるblockTypeとCreateBlockType関数を以下のように記述してください。

CreateBlockType関数では、実際のテトリスでも見たことのある7種類のブロックタイプを定義しています。このブロックタイプを変えることにより様々なブロックの形状で遊ぶことも可能です。

このCreateBlockType関数をゲーム開始のタイミングで実行させたいため、BlockBazooka.csのStart関数を以下のように記述してください。

ブロックタイプを基にブロックユニットを作成

次に、BlockTypeから実際にブロックユニットを生成する関数を以下のように記述していきます。

今回は、第一引数のtypeNumを使用して、blockTypes中の好きな形状を生成する関数として作成しています。親オブジェクトであるblockUnitsにRigidbodyを割り当てFire関数で発射できるように設定しています。

二次元配列は正方行列なのでループの上限値はsizeで抑えています。
また、if(blockTypes[typeNum].shape[j,i]==1)に関しての注意点について。元々、iはx方向を、jはy方向でループを回しています。
ここで、shape[i,j]と記述するとshape[x方向, y方向]となり正しいように見えますが、
blockType[6].shapeの要素は以下のように参照できます。
shape[0,0] = 0 shape[0,1] = 1 shape[0,2] = 1
shape[1,0] = 1 shape[1,1] = 1 shape[1,2] = 0
shape[2,0] = 0 shape[2,1] = 0 shape[2,2] = 0
上の要素番号の流れをよく見ると、shapeの要素はshape[y方向, x方向]になっていることが分かります。
そのため、「shape(j,i)」と記述していることに注意してください。

このブロックユニットを生成すると、下のような親子関係で出力されます。

BlockUnitsは空のゲームオブジェクトで、複数の子オブジェクトがブロックユニットの形状になります。

Fire関数でblockUnitsを発射できるように、Update関数を以下のように書き換えてください。

さらに、Fire関数はCreateBlock関数で生成されたブロックユニットをそのまま発射するように、以下のように書き換えましょう。

ブロックユニットを使用するための設定

最後に、この状態でプレハブのBlockのRigidbodyを削除してください。削除はInspectorの右上のボタン→Remove Componentでできます。

今回、ブロックの一塊としてブロックユニットを作成し、それがくっついた時、子オブジェクトのブロックを配置するようにしています。子オブジェクトにRigidbodyが付いているとブロック同士が衝突してしまうため上手く飛ばなくなります。

では、この状態で実行してみてください。ブロックユニットが配置できるようになったでしょうか?

はみ出したブロックを配置させない処理

現在の状態のままだと、すでにブロックが存在する場所にブロックを重ねて配置出来てしまいます。それに対処するため、Field.csのOnCollisionEnter関数を編集していきます。

まず、冒頭のif文により、タグが”blockUnits”のゲームオブジェクトのみ処理されるようにします。

そして、以下のif文を使用して、フィールド外およびブロックが配置されていないかどうかをチェックします。

このCheckExistBlock関数は、次のように実装していきます。

これは、BlockUnitsの子オブジェクトの座標を基に、ブロックが配置できるスペースがあるかを検知する関数となっています。

では、OnCollisionEnter関数の説明に戻ります。複数個のブロックを同時に設定する処理は以下のように編集して実装しています。

このApplyBlockUnits関数は、次のように実装します。

最後に、Unity上でEdit→Project Settings→Tags and Layoutsから「blockUnits」というタグを作成してください。これで準備完了です。

最後に、BlockBazooka.csでblockUnitsゲームオブジェクトに今設定したtagを追加します。

 

実行すると、フィールド外やブロックが配置されているところに重ねて配置できなくなっている様子が確認できます。

【微修正】ブロックが引っかかる不具合の修正

現段階の状態だと、ブロックが引っかかるような挙動を起こすことがあります。この原因は、ブロックのColliderがほかのブロックと衝突しあってしまうためです。
そのため、3行だけ追加して修正します。

Field.csのOnCollisionEnter関数内を以下のように修正してください。

ここでは、衝突したブロックが配置できない場合、子オブジェクトのブロックのBoxColliderを削除する処理を実装しています。

この状態で実行してみてください。ブロックが引っかからなくなったと思います。

次回予告

次回は、ブロックが落ちる処理を実装していきます。

コメント

タイトルとURLをコピーしました