前回の作業でプレイヤーのアニメーションを用意できたので、次はいよいよプレイヤーを動かせるようにしていきます。具体的には「(プレイヤーが接地しているとき)Spaceキーを押したらプレイヤーがジャンプする」というような挙動を作ります。
これを実現するためにC#スクリプトを書いてもいいのですが、今回はUnity2021の新機能である「Visual Scripting」を活用して、1行もスクリプトを書かずに簡単にプレイヤーの動きを作ってみましょう。
※注意:
Visual Scriptingの使い方は文章だと説明しづらくて長文になってしまいました。説明を読んだだけでは分かりづらいと思いますが、実際にやってみると簡単なのでぜひUnityを操作しながら読んでいただければと思います。
プレイヤーを動かすための準備
物理演算機能の追加
では、まずは準備としてPlayerオブジェクトに
- Rigidbody 2D
- Capsule Collider 2D
をアタッチして、下の画像のように設定してください。
- 重力スケール:
デフォルトだと落下がゆっくりすぎるので、大きめの値を設定 - 衝突判定:
「連続的」に設定。当たり判定が小さく・かつ動きが速い物体の場合は「すり抜け」が発生することがあるが、この設定にすることでそれを防止できる(※今回の場合はまず大丈夫だと思いますが念のため)。 - スリープモード:
「スリープしない」に設定。物理演算ではしばらく動かないとスリープ状態になり、他の物体に当たったかどうかの判定が上手く行われない場合があるため、それを防止する - 回転を固定:
ONにする。こうしないとプレイヤーがコケてしまうことがある
ちなみにRigidbody 2Dは2Dゲーム用の物理演算を行うためのコンポーネント、Capsule Collider 2Dは2Dゲーム用のカプセル状の当たり判定のコンポーネントです(※それぞれ3D用のものもあります。間違えないように注意!)。物理演算を行うときは当たり判定のコンポーネントもセットでアタッチしないと「すり抜け」が起きてしまうため注意してください。
あと、今回のプレイヤーの動きは別に物理演算を使わなくても実現できるのですが、Rigidbodyを使うと簡単なのでこのような準備を行っています。
レイヤーの設定
そうしたらPlayerオブジェクトのレイヤーを変更します。レイヤーを設定することで、例えば物理演算のときなどに「このレイヤー同士は衝突しないですり抜ける」といった挙動にすることが可能です。
やり方は、まずProject Settingsウィンドウを開き、「タグとレイヤー」タブの「レイヤー」10番に「Player」と入力してください(下図)。
できたらPlayerオブジェクトの「レイヤー」のドロップダウンメニューから今作った「Player」を選択しておきましょう。これで準備完了です。
Visual Scriptingでプレイヤーを動かす方法
次にここからが本題で、Visual Scriptingを使ってプレイヤーを動かすロジックを組んでいきます。Visual Scriptingの使い方は簡単なので、今まで使ったことがない方でも下記のやり方をよく読んでいただければ問題なく作れると思います。ここでの主な手順は次の通りです。
- 必要なコンポーネントをアタッチする
- Script Graphを新規作成する
- Script Graphを編集する
手順1:必要なコンポーネントをアタッチする
まずはVisual Scripting用のコンポーネントをアタッチします。インスペクターでPlayerオブジェクトを開き、「Add Component」→「ビジュアルスクリプティング」→「Script Machine」を選択しましょう。
すると上の図のように
- Script Machine
- Variables
という2つのコンポーネントがアタッチされ、さらにヒエラルキーに「Scene Variables」というゲームオブジェクトが新しく追加されます。
手順2:Script Graphを新規作成する
そうしたら次はVisual Scriptingのデータを格納するための「Script Graph」を新規作成します。「Script Machine」コンポーネントの「Graph」のところにあるNewボタンをクリックし、適当なフォルダに新しいScript Graphを作ってください。
手順3:Script Graphウィンドウを開いて編集する
これでVisual Scriptingを使うための準備ができたので、「Edit Graph」ボタンをクリックしScript Graphウィンドウを開いて編集を始めましょう。初期状態では下の図のような画面になっています。
ここに「ユニット」と呼ばれる機能の単位(※上の図で言うと、StartとかUpdateと書かれた四角いのがユニットです)を追加し、そのユニット同士を繋いでいくことでプレイヤーを動かすロジックの流れを作っていきます。
ユニットには「ポート」と呼ばれる接続端子のようなものがあり、左側が入力ポート・右側が出力ポートとなっています(つまりVisual Scriptingでは必ず左から右へと処理が流れることになります)。
また、ポートには次の2種類があります。
- Control Port:処理の流れを示すポート(三角形の端子)
- Value Port:何らかの値を入出力するためのポート(丸い端子)
Control Portには同じくControl Port、Value Portには同じ型のValueポートを繋ぐことができます。接続方法は、出力ポートの部分を左クリックすると線が伸びるので、それを繋ぎたい入力ポートの上に持って行って左クリックするだけです。
完成図
さて前置きが長くなりましたが、ここからプレイヤーの動きの処理を作っていきます。初めに完成図を掲載しておきますので、これを見ながら作業していってください。
図のA部、B部に分けてそれぞれ説明していきます。
処理A:接地判定
まず処理Aの部分は接地判定です。簡単に言うとRaycastというセンサー的な機能を使ってプレイヤーの真下をチェックし、地面などのコライダーがあるかどうかを調べます(※他にもやり方はありますが、これが一番堅実な方法です)。
ではこの部分の処理がどういう仕組みになっているのかを説明しつつ、作り方の手順を書いていきますね。
Raycast(※2D用)のユニットを追加する
最初に、この部分の肝となる処理である2D用のRaycastユニットを追加します。右クリック→出てきたメニューの検索バーに「physics2d raycast」と入力し、検索結果に出てくる
という項目をクリックしましょう(※同じユニットでも引数が違うものが検索結果に出てくるので、間違えないように気を付けてください)。
そうすると新しいユニットが画面に追加されるので、これの入力用Control PortとUpdateイベントの出力用Control Portを繋いでください。
Raycastユニットの設定&必要なユニットを接続する
さてRaycastユニットの引数は
- Origin:センサーの原点
- Direction:センサーで調べる方向
- Distance:センサーの検出距離
- Layer Mask:センサーの検出対象となるレイヤー
なので、これらの情報が必要です。そこで値を直接入力したり、値を取得するノードを使ったりして対応します。
Origin
まずOriginには「プレイヤーキャラクターの座標」を指定したいので、「Get Position」ユニットを新規作成して接続します。
Direction
次にDirectionには「ワールド座標の下方向」を指定したいので、直接(0, -1)と入力します。なおこれはユニットから取得することもできますが、今回は直接書いてしまった方が速いです。
Distance
Distanceには直接「0.1」を指定します。この値が大きすぎると、見た目では接地していなさそうに見えても接地していると判定されるので注意しましょう。
Layer Mask
最後にLayer Maskには、レイヤーを指定できる「Layer Mask」ユニットを接続します。新しくLayer Maskユニットを作り、ドロップダウンから「Default」レイヤーを指定しましょう。こうすることでDefaultレイヤーになっているゲームオブジェクトだけ検出対象になります(※例えば、プレイヤーはPlayerレイヤーなので除外されます)。
Nullチェックを行うユニットを配置する
さて、これで地面を検出するための処理ができたので、ここから先は
- 地面に接地している場合
- 空中にいる場合
で分岐させようと思います。
しかしここにはちょっとした落とし穴があります。それは2D用のRaycastは「RaycastHit2D」という型のデータを戻り値として返すということです。つまりifユニットで条件分岐できないので、ここでは別の方法で分岐させる方法が必要です。
そこで今回は次のような方法を採用します。
- RaycastHit2D型には、Raycastユニットで検出したゲームオブジェクトのコライダーを格納する変数がある
- その変数は、何も検出されなかった場合には「null」(=つまり何もない)が格納される
- したがってNullチェックを行い、戻り値のRaycastHit2Dがnullの場合は接地しなかったと判定する
…なんかちょっと難しくなってしまいましたが、とりあえず「ifユニットが使えないから、仕方なくNullチェックという方法で対応するんだな」くらいに思って頂ければ大丈夫です。
それでVisual Scriptingにはご丁寧に「Null Check」というユニットがあるので、それを使わせてもらいましょう。Null Checkユニットを新規作成してControl PortをRaycastユニットと繋いでください。
そうしたら、あとはRaycastユニットの戻り値のRaycastHit2Dからコライダーの有無を取得するだけです。RaycastHit2D用の「Get Collider」というユニットがあるので、それを新規作成してお手本のように接続しましょう。
処理B:入力判定&ジャンプ処理
さてさて、ここまででやっと半分です。もう半分の処理はそんなに難しくないのでサクッと作ってしまいましょう。
プレイヤーのアニメーションを切り替える
まず、接地状況によってプレイヤーのAnimatorの値を切り替えてアニメーションを変更します。Animatorの「Set Bool」ユニットを2つ作り、上の図のように設定してください。
入力を取得する
次に、接地している場合は入力をチェックします。Inputの「Get Buton Down」ユニットを作成し、Button Nameに「Jump」(※)を指定してください。
※注:
「Jump」はデフォルトで設定されている入力名で、キーボードでいうとSpaceキーが割り当てられています。
もし入力があったらジャンプさせる
最後に入力があった場合のみジャンプさせる処理を作ります。こちらはIfユニットで分岐できるので、Ifユニットを新規作成して入力結果を受け取るようにします。
そしてTrueの先にはRigidbody 2Dの「Add Force」ユニットを作成します(※引数が「Force」と「Mode」のものを選択してください)。引数の値は直接
- Force:「20」
- Mode:「Impluse」
と指定しましょう。ちなみにModeが「Impluse」だと一瞬だけ力を加えられたような動きをするので、ジャンプの挙動を作るにはもってこいです。
テストプレイして動作を確認しよう
ここまでお疲れさまでした。これでプレイヤーのジャンプ処理を作ることができたので、さっそく再生ボタンを押してテストプレイしてみましょう。
プレイヤーが次のGIFのように動けばOKです(Spaceキーでジャンプ)。