【Unity】キーボードでキャラクターを操作する
更新事項
本記事は2023/9/10に対象とするUnityのバージョンを変更してリライトしています。
概要
以前に以下の記事でUnityの新規プロジェクトの作成からUnity Assetとして提供されているキャラクターオブジェクトの「Robot Kyle」をSceneへ配置するところまでの流れを紹介しました。
今回はその続きとしてキーボード入力でRobot Kyleを操作する方法について紹介していきます。
体系的にUnityを理解したい場合は本で勉強するのがおすすめです
環境
- Windows11 Home
- Unity Hub 3.5.0
- Unity 2022.3.7f1
目的
キーボード入力によるキャラクター(RobotKyle)の移動操作を目指します。具体的には以下を行えるようにしたいと思います。
- キーボードの↑↓ボタンで前後に進む
- キーボードの←→ボタンで方向転換する
- スペースキーでジャンプする
- Shift + ↑↓ボタンでダッシュで前後に進む
今回はキャラクターにアニメーションは付けずに、初期姿勢のままの動かすというところまでを目指します。
Step1 : コンポーネント類の追加
Robot Kyleを動かすにあたり物理計算を行うためのRigidbodyと、衝突を管理するためのColliderのコンポーネントを設定していきます。
Rigidbodyの追加
まずはRigidbodyを追加します。Rigidbodyを設定することで物体に質量を設定したり、重力の影響を受けるようにすることができます。重力を設定しておかないと、ジャンプした後に降りてこれないので重要です。
[Robot Kyle]を選択した状態で、InspectorタブからAdd Componentを選択します。
Rigidbodyの[Constrains]の中に[Freeze Rotation]という項目があるので、[X], [Y], [Z]それぞれにチェックを入れておきます。これにチェックを入れておかないと、後のプログラムを動かした際にキャラクターが回転してしまいうまく動かないためです。ここにチェックを入れるかどうかはやりたいことやプログラムに依ります。
Rigidbodyの設定は以上です。
Colliderの追加
次にColliderのコンポーネントも追加していきます。Colliderは物体同士の衝突を扱うことができるComponentです。Colliderを設定しないとキャラクターが地面を貫通して下に落ちて行ってしまうことになるので設定が必要です。
[Add Component] > [Physics] > [Capsule Collider]を選択します。Capsule Colliderは楕円型の衝突検知範囲のようなもので、人型のキャラクターに設定する場合におすすめです。Capsule Colliderの設定値はうまいくRobot Kyleの体が収まるくらいに調整するのが良いです。今回の例では以下のように設定しています。
Y | 0.9 |
Radius | 0.3 |
Height | 1.8 |
設定すると以下のようにキャラクターの周りに緑色の枠が表示されます。これがCapsule Colliderです。うまくキャラクターが収まっていれば大丈夫です。
Step2 : Main Cameraの設定
次にMain Cameraの設定を行います.Main Cameraを設定する理由はGameモードでキャラクターを操作する際、キャラクターの背後を見ながら操作できるようにするためです。操作しやすい場所にカメラを設定します。
まずはキャラクターの移動に合わせてカメラも追従する必要があるため、Main CameraをRobot Kyle内のオブジェクトとして移動します。
Hierarchyの[Main Camera]をドラッグ&ドロップで[Robot Kyle]に持っていくことで移動させることができます。
次に、Main Cameraの[Inspector]で[Transform]を調整します。これを調整することで後ろからキャラクターを見る際の見え方をいい感じにすることができます。
設定値は好みになりますが、私の場合はRobot Kyleのなるべく全身を映るようにしたかったため、以下のように設定してあります。
X | 0 |
Y | 1.5 |
Z | -2.5 |
Step3: Terrianへのタグ付け
キャラクターがジャンプ中なのか地面に接地しているのかを判定するため、TerrianにGroundタグをつけて、Groundに接触している場合には接地しているという判定をすることにします。そのための準備としてTerrianにGroundタグをつけておきます。Groundタグを作っていない場合はAdd Tagから「Ground」という名前を付けたタグを作って設定してください。
Step4: 操作スクリプトの作成
いよいよRobotKyleを操作するためのスクリプトを作成していきます。
[Add Component] > [New Script]からスクリプトファイルを作成します。Nameは自由に決められますので、ここでは[PlayerController]という名前にしました。これにより、Componentにスクリプトファイルが追加されます。メニューから[Edit Script]を押すとエディタが立ち上がります。私の環境ではVSCodeをインストールしていたのでVSCodeが立ち上がり、編集できるようになりました。
作成したスクリプトに操作の部分を書いていくのですが、大まかに以下の方針で進めることにしました。
- 移動はTransform.positionを使用して制御する。
- ジャンプ中に空中で移動はできないようにする
- 斜め前にもジャンプできるようにする
- 二段ジャンプは禁止する
これを実現したスクリプトが以下になります。
スクリプト全体
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// Start is called before the first frame update
//ステータス初期化
[SerializeField] public bool onGround = true;
[SerializeField] public bool inJumping = false;
//Rigidbody定義
Rigidbody rb;
//移動スピード定義
float speed = 6f;
//ダッシュスピード定義
float sprintspeed = 9f;
//方向転換速度定義
float angleSpeed = 200;
//移動量変数定義(v:水平方向、h:垂直方向)
float v;
float h;
void Start()
{
//Rigidbody componentを取得
rb = this.GetComponent<Rigidbody>();
}
void Update()
{
//Shift+上下キーでダッシュ、上下キーで通常移動、それ以外は停止
if (Input.GetKey(KeyCode.UpArrow) && Input.GetKey(KeyCode.LeftShift))
v = Time.deltaTime * sprintspeed;
else if (Input.GetKey(KeyCode.DownArrow) && Input.GetKey(KeyCode.LeftShift))
v = -Time.deltaTime * sprintspeed;
else if (Input.GetKey(KeyCode.UpArrow))
v = Time.deltaTime * speed;
else if (Input.GetKey(KeyCode.DownArrow))
v = -Time.deltaTime * speed;
else
v = 0;
//移動の実行
if (!inJumping)//空中での移動は禁止
{
transform.position += transform.forward * v;
}
//スペースボタンでジャンプする
if (onGround)
{
if (Input.GetKey(KeyCode.Space))
{
//ジャンプさせるため上方向に力を発生
rb.AddForce(transform.up * 8, ForceMode.Impulse);
//ジャンプ中は地面との接触判定をfalseにする
onGround = false;
inJumping = true;
//前後キーを押しながらジャンプしたときは前後方向の力も発生
if (Input.GetKey(KeyCode.UpArrow))
{
rb.AddForce(transform.forward * 6f,ForceMode.Impulse);
}
else if (Input.GetKey(KeyCode.DownArrow))
{
rb.AddForce(transform.forward * -3f, ForceMode.Impulse);
}
}
}
//左右キーで方向転換
if (Input.GetKey(KeyCode.RightArrow))
h = Time.deltaTime * angleSpeed;
else if (Input.GetKey(KeyCode.LeftArrow))
h = -Time.deltaTime * angleSpeed;
else
h = 0;
//方向転換動作の実行
transform.Rotate(Vector3.up * h);
}
//地面(Groundタグ)に接触したときにはonGroundをtrue、injumpingをfalseにする
void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag=="Ground")
{
onGround = true;
inJumping = false;
}
}
}
スクリプトの中身について順を追って説明します。
void Start部
今回、Playerの回転を止める際とジャンプするための力を発生させるためにRigidbodyを使用します。そのため初めにPlayerのRigidbody関連のオブジェクトを取得しておきます。
void Update部
前後方向の移動速度定義
押下しているキーに応じて前後方向の速度を変化させています。
Shiftと方向ボタンを押したときはダッシュ速度(sprintspeed)、方向ボタンの場合は通常移動速度(speed)を使用しています。
ジャンプ
ジャンプする条件としてスペースキーの押下とキャラクターが地面に接触していることとしています。これにより空中での二段ジャンプを禁止しています。
方向転換
- 方向転換のベクトル定義
- transform.Rotateで回転
Addforceを使用して上方向の力を発生させることでジャンプをさせています。また、前後方向キーを押しながらスペースキーを押すことで、前方向の力も同時に発生させ、斜め前にジャンプするようにしています。後ろ向きの場合は少し力を弱めています。
OnCollisionEnter
キャラクターが地面と接触した場合にはonGroundをtrueにします。また、inJumpingをfalseにします。地面と接触したかどうかについては、Terrianに設定したGroundタグを使用します。
上記のコードでうまく動かない場合には以下をチェックしてみてください。
- TerrianにGroundタグが付いているか
- Robot KyleのRigidbodyでFreeze Rotationの各座標にチェックを入れているか
Step5:動作確認
早速Gameモードで実行します。
キーボードを動かして移動やジャンプ、ダッシュなどができるか確認してみてください。
次回
今回はキーボードでRobot Kyleを動かすところまでを実践しました。ただ、この状態だとまだアニメーションがついていないので、味気なくなっています。次回はさらにこのスクリプトを改良し、アニメーションをつけていきたいと思います。
以上
すみません、コメントを失礼します。
スクリプト全体のプレイヤー操作がStartメソッド内に書いていますが、
Updateメソッドが正しい気がしてます。
ご指摘ありがとうございます。訂正させていただきました。諸事情で現在検証環境が無くチェックが甘い箇所があるかもしれませんがご容赦ください。