こんにちは、”しん” です。
ゲーム制作を初めてまだ間もないので、次に取り組むゲーム制作は何にしようかと考えた時、既存のゲームシステムを真似て自分のオリジナリティを加える方法が一番取り組みやすそうだと思ったので、まず手始めに「ブロック崩し」から作ってみようと考えました。
よく無料ゲームとかアプリで見るあれです。
将来的には3Dゲームを作っていきたいので、あえて2Dではなく3Dで作っていこうと思います。(2Dゲームにも、3Dゲームを作っている傍ら触れていきたい。)
Contents
ブロック崩しには何が必要?
ブロック崩しに最低限必要そうなのはおそらくこの4つだと思います。
- ステージ
- ボール
- バー
- ブロック
その後ボールの挙動やブロックの消去などを作って、「ボールが増える」とか「ブロックを動く敵にする」だとかいう要素を加えたらオリジナリティあるものが作れそうです。
とりあえずバーが動くようにする
ステージの上でボールを跳ねさせられるように、バーをドラッグで動かしてボールを跳ねさせるようなシステムを作ってみます。
簡単なブロック崩しなら左右の方向キーだけで操作すると思いますが、それだけでは何か物足りないと思ったので、raycastを用いて自由にドラッグできるようにしてみました。(方向キーだけにして、もっと制作を進めても良かったのかもしれない…)
ステージを作る
簡単に、これから使うステージを作ります。本当に簡単にです。
こんな感じでステージを作った後に、ステージを斜め上からメインカメラで俯瞰できるような位置に移動させて、ゲームの画面を作成します。
Raycastを使用してバーを動かす
次に、raycastという機能を用いてバーをドラッグで動かせるようにしてみます。
Raycastというのはある地点からある地点へray(光線)を飛ばして、それに当たったオブジェクトの情報を取得するような機能です。
FPSゲーム等で銃を撃ったときの当たり判定や今回のようなドラッグ&ドロップなどの機能をRaycastを使って実現することができます。
このゲームを作り始める時点で、筆者はraycastについて知識程度しかなかったので、実際に実装してみると結構苦労しました。
バーにcolliderを適用する
適当に配置したバーを選択して、colliderをつけます。
colliderは Inspector > Add Component からcolliderと検索をすれば色々なcolliderが出てくるので、バーにあったcolliderを選んでください。画像ではMesh Colliderを選んでいますが、Box Colliderでも大丈夫です。
カメラの位置を動かす
カメラの位置をずらして、ゲームシーンでステージを俯瞰できるようにします。
より詳細なカメラの位置を自分で決めたい場合には、Main Cameraを選んだ状態でSceneをゲームビューにしたい画角に調整した後、Macならcommand + shift + F, WindowsならControl + shift + F で現在のSceneの画角をそのままMain Cameraの画角とすることができます。
バーが動いていることが確認できる位置、もしくは最終的なゲーム画面の視点であれば基本的にはどこでも問題はありません。
raycastがうまく動作しているか確かめる
raycastを使ってバーをドラッグするシステムを実現するために、まずraycastがうまく動作するのか確認してみようと思います。
確認に使ったプログラムはこちらになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RayCheck : MonoBehaviour
{
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Raycheck();
}
}
private void Raycheck()
{
RaycastHit rayhit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out rayhit, Mathf.Infinity))
{
if(rayhit.collider.tag == "Bar")
{
print("hit!");
}
}
}
}
このプログラムでは、rayの届く範囲を無限にして、一番初めにrayと衝突したオブジェクトのタグがBarだったときに “hit!” と表示するようにしています。
このように、バーに当たった場合に”hit!”と表示されているのでraycastの動作は確認できました。
ちなみに、rayの長さを有限にした時に”hit!”という表示が出ない場合に考えられる原因は、rayが届いていない、もしくはcolliderを設定していない等のエラーなどが考えられますが、もしrayが届いていなかった場合、これを確認するのは今の状態では難しいです。
そこで便利なのがraycastを可視化する方法。rayの定義の後に下のコードを適宜改変して追加すればrayの辿った道を可視化して、実際に当たっているかどうか確認することがきます。
Debug.DrawRay(ray.origin, ray.direction * (rayの長さ), Color.red, (表示させたい時間));
公式のドキュメントはこちらになります。
平面上を動くようにする
raycastが動作していることは確認できたので、あとはドラッグしている間マウスカーソルに合わせてオブジェクトが動くようにしたら完成です。
ここで問題になるのが、バーの動かし方。
今ゲームビュー(Main Camera)上でマウスカーソルでオブジェクトをドラッグ&ドロップをすると、下の図のように画面と平行に動くようになってしまいます。
これだと、もちろんブロック崩しのバーとして役割を果たさないので、なんとかして下の図のように平面(ステージ)上を動くようにします。
平面上で動くようにするため、以下のようなスクリプトを記述しました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BarControl : MonoBehaviour
{
private Plane table;
private Transform bar;
private bool drag = false;
void Start()
{
var ppos = new Vector3(0, 0.15f, 0);
table = new Plane(Vector3.up, ppos);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Raycheck();
}
if (drag)
{
Dragbar();
}
if (Input.GetMouseButtonUp(0))
{
drag = false;
}
}
private void Raycheck()
{
RaycastHit rayhit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out rayhit, Mathf.Infinity))
{
if (rayhit.collider.tag == "Bar")
{
drag = true;
bar = rayhit.transform;
}
}
}
private void Dragbar()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float rayDistance;
table.Raycast(ray, out rayDistance);
transform.position = ray.GetPoint(rayDistance);
}
}
こちらのスクリプトは下記の記事を参考にさせていただきました。
参考 【Unity】ドラッグアンドドロップで3Dオブジェクトを動かすUnityの使い方|初心者からわかりやすく注目すべきなのはtableという新しいPlaneを作成して、Dragbarメソッドでtableに向かってraycastを使用している点です。
table = new Plane(Vector3.up, ppos);
この部分では、(0, 0.15f, 0)の位置に”見えないPlane”であるtableを配置するよう初期化しています。
Planeについての公式ドキュメントからわかるように、Planeの持つ引数の1つ目は法線ベクトルで、2つ目はワールド座標系の位置です。これによって平面の向きと位置を設定できます。pposを細かく設定しているのはバーの大きさに合わせるためです。
参考 PlaneUnity DocumentationDragBarメソッドでは、tableにreycastをして、その座標を返すようにしています。これによってrayが届いた平面上の位置にオブジェクトが移動してくれるようになります。
実行結果
実行してみるとこのような感じになりました。
ボールの当たり判定や跳ね返りなどはまだ設定していないため、ボールに当たってもすり抜けたりしてしまうので、次回からはその点を直しながら開発を進めていこうと思います。
まとめ
今回の記事ではraycastとドラッグ&ドロップの実装はできましたが、ボールとの当たり判定やブロックの生成など、基本的なブロック崩しの要素はまだできていないので、次回から取り組んでいこうと思います。
特に、ボールの当たり判定や跳ね返りなどは今の時点でも上手くいっていないため、どうしたら上手く跳ね返るか、ブロック崩しのボールの動きに近づけることができるかを考えながら実行する必要がありそうです。
ちなみに、raycastはあまり使いすぎると結構重い処理になるらしいので、あまり多用せず開発していきたいですね。