6-7で入力が受け取れるようになったので、いよいよキャラクターを動かしていきます!オブジェクトの位置の変え方、どのパソコンでも同じ速さで動かすためのTime.deltaTime、進む方向を向かせる方法まで、プレイヤーの移動に必要なことをまとめてご紹介します。
この記事で学べること
transform.positionでオブジェクトの位置を変える方法- Vector3の足し算・掛け算と、よく使う方向(Vector3.forwardなど)
- Time.deltaTimeで、FPSに関係なく同じ速さで動かす方法
- 斜め移動が速くならないようにする方法(normalized)
- 進む方向にオブジェクトを向かせる方法
- Rigidbodyで動かす場合の書き方
前提知識
位置を変える:transform.position
位置を直接指定する
オブジェクトの位置は、transform.position(Vector3)で読み書きできます:
// 今の位置を読む
Vector3 currentPosition = transform.position;
// 指定した場所に移動させる(ワープ)
transform.position = new Vector3(1f, 0f, 0f);
transform.positionはワールド座標(シーン全体での位置)です。親から見た位置はtransform.localPositionで読み書きできます(3-2の記事で説明した、ワールド座標とローカル座標の違いです)。
少しずつ動かす
毎フレーム少しずつ位置を足していくと、オブジェクトが動いて見えます:
void Update()
{
// 毎フレーム、右(X軸のプラス方向)に少しずつ動かす
transform.position += new Vector3(0.01f, 0f, 0f);
}
Vector3のよく使う書き方
方向の決まった値
| 書き方 | 値 | 意味 |
|---|---|---|
Vector3.zero | (0, 0, 0) | 原点、動かない |
Vector3.right | (1, 0, 0) | 右 |
Vector3.up | (0, 1, 0) | 上 |
Vector3.forward | (0, 0, 1) | 前(奥) |
Vector3.left(左)、Vector3.down(下)、Vector3.back(後ろ)もあります。
計算
Vector3 a = new Vector3(1f, 2f, 0f);
Vector3 b = new Vector3(3f, 0f, 0f);
Vector3 sum = a + b; // (4, 2, 0) それぞれを足す
Vector3 doubled = a * 2f; // (2, 4, 0) それぞれに掛ける
float length = a.magnitude; // 長さ(原点からの距離)
float distance = Vector3.Distance(a, b); // 2点の距離
「方向 × 速さ」で、どの向きにどれだけ進むかを表せます。
Time.deltaTime:どのパソコンでも同じ速さにする
1フレームごとに足すと、速さが変わってしまう
上の例の0.01fを毎フレーム足すやり方だと、
- 60FPSのパソコン:1秒で0.6進む
- 144FPSのパソコン:1秒で1.44進む
と、パソコンによって速さが変わってしまいます。
「1秒あたりの速さ × deltaTime」で解決
Time.deltaTimeは、前のフレームから何秒たったかです。
[SerializeField] private float moveSpeed = 5f; // 1秒あたりに進む距離
void Update()
{
transform.position += Vector3.right * moveSpeed * Time.deltaTime;
}
- 60FPS:1フレーム約0.016秒 → 1フレームで約0.08進む × 60回 = 1秒で5
- 144FPS:1フレーム約0.007秒 → 1フレームで約0.035進む × 144回 = 1秒で5
Updateで動かすときは、速さにTime.deltaTimeを掛ける。これだけ覚えておけばOKです。
スライム自分のパソコンではちょうどいいのに、友だちのパソコンだと爆速に・・・



それはTime.deltaTimeの掛け忘れのサインだね!動きや回転の速さには、必ず掛けるクセをつけよう
Translate:向いている方向を基準に動かす
transform.Translate()でも動かせます。こちらはオブジェクトが向いている方向を基準に動きます。
// オブジェクトの「前」に進む(回転していれば、その向きの前)
transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
// 向きに関係なく、ワールドの「前」に進む
transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime, Space.World);
| 書き方 | 基準 |
|---|---|
transform.position += 方向 | ワールド(シーン全体) |
transform.Translate(方向) | オブジェクト自身の向き |
transform.Translate(方向, Space.World) | ワールド |
車のように「向いている方向に前進」ならTranslate、見下ろし型のように「画面の上に進む」ならposition +=が分かりやすいです。
入力で動かす:プレイヤーの移動スクリプト
6-7で作った入力と組み合わせて、見下ろし型のプレイヤーを作ってみましょう。
準備
- Universal 3Dのプロジェクトで、Hierarchyで右クリック>3D Object>Planeを作る(床)
- Hierarchyで右クリック>3D Object>Capsuleを作り、名前をPlayerにする(Position Yを1にして床の上に置く)
- Main Cameraを、Playerを斜め上から見下ろす位置に置く(例:Position (0, 10, -8)、Rotation (50, 0, 0))
- 6-7のGenerate C# Classが済んでいることを確認
スクリプト
「PlayerMover」という名前でスクリプトを作り、Playerにアタッチします。
using UnityEngine;
public class PlayerMover : MonoBehaviour
{
[SerializeField] private float walkSpeed = 4f;
[SerializeField] private float runSpeed = 8f;
[SerializeField] private float turnSpeed = 720f; // 1秒あたりに回転する角度
private InputSystem_Actions inputActions;
void Awake()
{
inputActions = new InputSystem_Actions();
}
void OnEnable()
{
inputActions.Enable();
}
void OnDisable()
{
inputActions.Disable();
}
void Update()
{
// 入力(x:左右、y:上下)を、3Dの床の上の方向(x:左右、z:奥・手前)にする
Vector2 input = inputActions.Player.Move.ReadValue<Vector2>();
Vector3 direction = new Vector3(input.x, 0f, input.y);
// 斜めに入力しても速くならないように、長さを1以下にそろえる
if (direction.magnitude > 1f)
{
direction = direction.normalized;
}
// 入力がないときは何もしない
if (direction == Vector3.zero)
{
return;
}
// Shiftを押している間は走る
float speed = inputActions.Player.Sprint.IsPressed() ? runSpeed : walkSpeed;
transform.position += direction * speed * Time.deltaTime;
// 進む方向に、少しずつ向きを変える
Quaternion targetRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
}
}
再生して、WASDで動き、Shiftで速くなり、進む方向を向けば成功!
スクリプトのポイント
- 入力の向きを3Dの向きに変える
- Moveの入力はVector2(x:左右、y:上下)
- 床の上を動く3Dゲームでは、上下の入力をZ軸(奥・手前)に使うので
new Vector3(input.x, 0f, input.y)にします - 2Dゲームなら、そのまま
new Vector3(input.x, input.y, 0f)でOKです
- normalized(ノーマライズ)
- 右と上を同時に押すと、方向は(1, 0, 1)になり、長さが約1.41になります。そのままだと斜めだけ1.4倍速くなってしまうので、長さを1にそろえます
- ゲームパッドのスティックを少しだけ倒したときは長さが1より小さいので、そのときはそのまま使います(ゆっくり歩ける)
条件 ? A : B- 条件がtrueならA、falseならBになる書き方です。ifで書くと次と同じ意味です
float speed;
if (inputActions.Player.Sprint.IsPressed())
{
speed = runSpeed;
}
else
{
speed = walkSpeed;
}
- 向きを変える
Quaternion.LookRotation(direction):その方向を向いたときの回転Quaternion.RotateTowards(今の回転, 目標の回転, 最大の角度):目標に向かって、決まった角度ずつ回す。一瞬で振り向かせたいときはtransform.rotation = targetRotation;だけでもOKです
Rigidbodyで動かす場合
壁にぶつかって止まる、押し返される、などの物理的な動きをさせたいときは、Rigidbodyを付けてRigidbodyに動かしてもらいます。
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PhysicsMover : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
private InputSystem_Actions inputActions;
private Rigidbody rb;
private Vector3 direction;
void Awake()
{
inputActions = new InputSystem_Actions();
rb = GetComponent<Rigidbody>();
}
void OnEnable()
{
inputActions.Enable();
}
void OnDisable()
{
inputActions.Disable();
}
void Update()
{
// 入力はUpdateで読む
Vector2 input = inputActions.Player.Move.ReadValue<Vector2>();
direction = Vector3.ClampMagnitude(new Vector3(input.x, 0f, input.y), 1f);
}
void FixedUpdate()
{
// 物理の動きはFixedUpdateで。上下の速さ(重力)はそのまま残す
Vector3 velocity = direction * moveSpeed;
velocity.y = rb.linearVelocity.y;
rb.linearVelocity = velocity;
}
}
rb.linearVelocity:Rigidbodyの速度(1秒あたりに進む量)。Unity6でvelocityから名前が変わりました。古い記事のrb.velocityは、今はrb.linearVelocityと読み替えてください- FixedUpdate:6-3で説明した、物理演算と同じ間隔で呼ばれるメソッド。Rigidbodyを動かす処理はここに書きます
- 速度そのものを指定しているので、
Time.deltaTimeは掛けません(Rigidbodyが時間に合わせて動かしてくれます) Vector3.ClampMagnitude(方向, 1f):長さを1以下にする書き方で、上のnormalizedのif文と同じ役割です[RequireComponent(typeof(Rigidbody))]:このスクリプトを付けると、Rigidbodyも自動で付けてくれます- キャラクターが転がってしまう場合は、RigidbodyのConstraints>Freeze RotationのX・Zにチェックを入れます
transform.positionで動かすと、壁の中にめり込んだりすり抜けたりすることがあります。壁や床との当たり判定が大事なキャラクターはRigidbodyで動かす、と覚えておきましょう。
よくあるエラーと対処法
エラー:動かない
- 原因:6-7の
inputActions.Enable()をしていない、速さの値が0になっている、またはスクリプトにエラーがある - 対処法:Inspectorの速さの値と、Consoleのエラーを確認する
エラー:パソコンによって速さが違う
- 原因:Updateで動かしているのに
Time.deltaTimeを掛けていない - 対処法:速さに
* Time.deltaTimeを掛ける
エラー:斜めだけ速い
- 原因:方向の長さを1にそろえていない
- 対処法:normalizedまたは
Vector3.ClampMagnitude(方向, 1f)を使う
エラー:思った方向と違う方向に進む
- 原因:
Translateはオブジェクトの向きが基準。回転させたオブジェクトで使うと、ワールドの方向とずれる - 対処法:ワールドの方向で動かしたいときは
transform.position +=か、Translate(方向, Space.World)を使う
エラー:’Rigidbody.velocity’ is obsolete
- 原因:Unity6では
velocityの名前が変わった - 対処法:
linearVelocityに書き換える
まとめ
- 位置は
transform.position。少しずつ足すと動いて見える - Updateで動かすときは、速さ × Time.deltaTime
- 斜め移動はnormalizedで長さをそろえる
- 進む方向を向かせるのは
Quaternion.LookRotationとRotateTowards - 物理的な動きが大事なときは、Rigidbodyの
linearVelocityをFixedUpdateで設定する
次のステップ
- よく使うUnity専用の関数とプロパティ:GetComponentやDestroyなど、スクリプトでよく使う機能
- Unityスタートガイド 目次
コメント
コメント一覧 (1件)
[…] オブジェクトを動かそう:位置・向き・Time.deltaTime […]