🌈 Unity ハンズオン · 入力と移動
Unityでクリックした場所に3Dモデルを移動させる方法
Raycast で地面の位置をゲット! 向きをなめらかに変えながら歩かせよう
ゴールは「クリックした床の場所にキャラが歩いてゆき、顔を進行方向に向ける」こと。 いきなり物理(Rigidbody)や経路AI(NavMesh)は使わず、Transform だけで中身が見えるカンタン実装にします。
自己紹介
オープニング対談
🎁このレッスンのおみやげ(学べること)
- 🖱️ クリックで「どこへ行くか」を決める流れ
- 📷
ScreenPointToRayで Ray 作成 - 🎯
Raycastで地面の座標ゲット - 🚶
MoveTowardsで歩かせる - 🔄
LookRotation+Slerpで向き変更 - 🏷️
LayerMaskで床だけ判定
このページの手順は Unity 向けです。Main Camera の ScreenPointToRay と Physics.Raycast が中心になります。
前提:シーンに「当たり判定のある地面」と「タグ付きメインカメラ」があること。
1👋導入 — いまからやること
このチュートリアルでは、画面上をクリックした場所に3Dモデルを移動させる処理を作ります。 キャラクターは移動先へ向かって進み、移動中は進行方向を向くようにします。
RPG、シミュレーション、クリック操作のアクションなどでよく使われる基本パターンです。 いきなり物理やAIを入れるとデバッグが難しくなるため、最初は Transform だけで成功体験をつくりましょう。
2🎬完成イメージ(ストーリー版)
完成後の動きは、次の通り。下のイラストとフロー図をあわせて読むとイメージがつかみやすいです。

- プレイヤーが画面上の地面をクリックする
- Camera からクリック位置へ Ray(見えない直線)を飛ばす
- Raycast で Ray が地面に当たった位置を 移動先として保存する
- 3Dモデルがその位置へ移動する
- 移動中、3Dモデルは移動方向を向く
- 目的地に近づいたら停止する
画面幅に応じて折り返します。横スクロールは不要です。
イメージのコツ
補足:Ray=3D空間のまっすぐな線。レイキャスト=その線がオブジェクトに当たったかを調べる処理。
3🧰使用するUnity機能(カードでざっと)
下のカードを上から順に追うと、このレッスンの骨組みが頭に入ります。
画面ピクセル → カメラから伸びる Ray を作成。
Ray が Collider に当たったか、どの点で当たったかを判定。
左クリックが押された瞬間だけ反応(押しっぱなしでは連打されません)。
キャラの「いまどこ」にあたる座標。ここを少しずつ動かして歩かせます。
毎フレームちょっとずつ目的地へ。ドリブルで運びやすい定番API。
くるりと回転を表す型。Euler角よりからまりにくいのが魅力。
ベクトルの向きを「顔の正面(Z+)」にそろえる回転を生成。
回転をなめらかにブレンド。キビキビ動きすぎ防止。
Raycast が反応するレイヤーを指定。床だけに絞るのが今回のミソ。
4🧱事前準備(シーンをかためる)
まずは小さなステージを用意します。難しく考えず、床・キャラ・カメラ・太陽の4点セットです。
- 🟫 Ground
- 🧍 Player
- 📷 Main Camera
- ☀️ Directional Light


- メニューから 3D Object → Plane を作成
- 名前を Ground に
- Mesh Collider(または Box Collider)が付いていることを確認
- 後述の手順で Layer を Ground に設定

- Capsule / Cube / 任意の3Dモデルを配置し、名前を Player
- 前後が分かりやすい形状にすると、向きの学習が楽です
- 見た目用モデルを 子オブジェクト に分ける構成も後半で解説します

- 地面と Player が見える位置へ移動・回転
- 例:Position(0, 8, -8)、Rotation(45, 0, 0)のような斜め上からの構図
- タグが MainCamera であることを確認(
Camera.mainに必要)
5🏷️レイヤーと LayerMask
クリック対象を地面だけにしたいので、LayerMask を使います。 LayerMask を使うと、Raycast が「どのレイヤーの Collider にだけ反応するか」を制限できます。 壁やアイテムを誤って目的地にしない、UIと干渉しにくくする、といった理由でも重要です。
なぜ Layer? というお話
- Unity 上部メニューまたは Inspector の Layer ドロップダウンから Edit Layers…
- 空いている User Layer に Ground を追加
- Ground オブジェクトの Layer を Ground に設定
- 後述のスクリプトで
groundLayerに Ground をチェックして指定
6📝スクリプト:ClickMoveController.cs
どのオブジェクトにアタッチする?
このスクリプトは、動かしたいキャラクター(Player)が付いているゲームオブジェクトにアタッチします。 Hierarchy で事前準備で置いた Player(Capsule など)を選び、Inspector の Add Component から ClickMoveController を追加するのがわかりやすいです。
地面(Ground)やMain Cameraには付けません。 transform.position や transform.rotation を書き換えているのは「このコンポーネントが付いたオブジェクト」だからです。
コメント多めなので、行の意味を追いながらコピー&ペーストして構いません。
using UnityEngine;
/// <summary>
/// 画面クリックで地面(指定レイヤー)上の点へ移動し、
/// 移動中は進行方向をなめらかに向けるシンプルなコントローラです。
/// Rigidbody / NavMesh は使いません(Transform ベース)。
/// </summary>
public class ClickMoveController : MonoBehaviour
{
[Header("移動設定")]
[Tooltip("1秒あたりの移動距離の目安。大きいほど速く進みます。")]
[SerializeField] private float moveSpeed = 5f;
[Tooltip("向きが変わる速さ。大きいほど素早く目的地の方向を向きます。")]
[SerializeField] private float rotateSpeed = 10f;
[Tooltip("目的地との距離がこの値以下になったら「到着」とみなして止まります。")]
[SerializeField] private float stopDistance = 0.05f;
[Header("クリック判定")]
[Tooltip("Raycast が反応するレイヤー。地面だけをオンにすると他のオブジェクトをクリックしても無視できます。")]
[SerializeField] private LayerMask groundLayer;
// 移動目標のワールド座標
private Vector3 targetPosition;
// 移動先が設定されているか(false ならその場に留まる)
private bool hasTarget;
private void Start()
{
// 初期位置をターゲットにしておくと、開始直後に誤って移動しにくいです
targetPosition = transform.position;
}
private void Update()
{
HandleClick();
MoveToTarget();
}
/// <summary>
/// 左クリックがあったら、カメラから Ray を飛ばして地面を探します。
/// </summary>
private void HandleClick()
{
// 0 = 左クリック。モバイル対応は別レッスンで Touch へ置き換えます。
if (!Input.GetMouseButtonDown(0))
{
return;
}
// マウス位置 → 3D 空間へ伸びる Ray(光線)
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// Ray を最大 100m 飛ばし、groundLayer だけに当たり判定
if (Physics.Raycast(ray, out RaycastHit hit, 100f, groundLayer))
{
targetPosition = hit.point; // 当たった表面の座標
hasTarget = true;
}
}
/// <summary>
/// 目的地へ少しずつ近づき、進行方向を向きます。
/// </summary>
private void MoveToTarget()
{
if (!hasTarget)
{
return;
}
Vector3 currentPosition = transform.position;
// Y は現在の高さを維持(キャラが地面にめり込まない / 浮かないよう水平移動)
Vector3 targetFlatPosition = new Vector3(
targetPosition.x,
currentPosition.y,
targetPosition.z
);
Vector3 direction = targetFlatPosition - currentPosition;
// 十分近ければ停止
if (direction.magnitude <= stopDistance)
{
hasTarget = false;
return;
}
// まず向きを合わせてから(または同フレーム内で)位置を進める
RotateToDirection(direction);
transform.position = Vector3.MoveTowards(
currentPosition,
targetFlatPosition,
moveSpeed * Time.deltaTime
);
}
/// <summary>
/// direction の向きを、なめらかに LOOK させる。
/// </summary>
private void RotateToDirection(Vector3 direction)
{
// ほぼゼロベクトルなら回転しない(エラー回避)
if (direction.sqrMagnitude <= 0.0001f)
{
return;
}
Quaternion targetRotation = Quaternion.LookRotation(direction.normalized);
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
rotateSpeed * Time.deltaTime
);
}
}7🔍コード解説(ねっこから理解)
7-1. 変数の説明
- moveSpeed:1秒あたりどれだけ進むかの目安。大きいほど速い。
- rotateSpeed:向きが変わる速さ。
Slerpの補間係数に掛け合わせます。 - stopDistance:この距離以下なら「着いた」とみなす。小さすぎると永遠に到達しようとしてガクガクすることがあります。
- groundLayer:Raycast が反応するレイヤー。地面だけオンにします。
- targetPosition:移動したいワールド座標。
- hasTarget:移動先が有効か。false のときは移動処理を省きます。
7-2. クリック位置を取得する処理
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 100f, groundLayer))
{
targetPosition = hit.point;
hasTarget = true;
}- Input.mousePosition は画面ピクセル座標(左下基準)。その位置から視線を伸ばすイメージ。
- ScreenPointToRay でその視線を Ray として表現。
- Physics.Raycast が地面の Collider に当たれば true。
- hit.point が「表面上の当たった地点」のワールド座標。
7-3. Y座標を固定する理由
Vector3 targetFlatPosition = new Vector3(
targetPosition.x,
currentPosition.y,
targetPosition.z
);地面をクリックした hit.point の Y をそのまま使うと、地面の微妙な傾きやメッシュの形状によってキャラの高さが毎回変わることがあります。キャラを水平移動だけさせたいなら、Y は現在の高さに固定して XZ 平面だけ動かすのが安全です。
7-4. 移動処理
transform.position = Vector3.MoveTowards(
currentPosition,
targetFlatPosition,
moveSpeed * Time.deltaTime
);- MoveTowards は毎フレーム「最大 moveSpeed * deltaTime だけ」近づきます。
- Time.deltaTime を掛けるとフレームレートに依存しにくく、遅いPCでも同じ速さに近づけます。
7-5. 移動方向を向く処理
Quaternion targetRotation = Quaternion.LookRotation(direction.normalized);
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
rotateSpeed * Time.deltaTime
);- direction は「今いる場所 → 目的地」へのベクトル。
- LookRotation でその方向を前に見る回転を生成。
- Slerp で直前の回転から滑らかに補間。 rotateSpeed を上げると素早く向きます。
8⚙️Unity エディタでやることリスト
- 1Player オブジェクトを選択する
- 2Project で作成した ClickMoveController.cs をドラッグ&ドロップでアタッチ
- 3Layer で Ground を作成し、Ground オブジェクトに適用
- 4Player の Inspector で groundLayer に Ground にチェックを付ける
- 5Play を押して、Scene ビューではなく Game ビューで地面をクリック
- 6Player が移動し、向きが変われば成功
9✔️動作確認チャレンジ
全部チェックできたら、今日のミッションクリアです 🎉
- 1地面をクリックすると Player が移動する
- 2Player がクリック位置の方向を向く
- 3目的地に近づくと停止する
- 4地面以外をクリックしても反応しない
- 5Player の高さが不自然に変わらない
10🆘つまずきポイント図鑑

例1:クリックしてもピクリともしない
原因の例:Ground に Collider がない / Ground Layer が未設定 / groundLayer に Ground が含まれていない / Camera.main が null。
対処:Collider と Layer を確認。Main Camera のタグが MainCamera か確認します。
例2:キャラがユニコーンみたいに上下に飛ぶ
原因:hit.point の Y をそのまま使っている。
対処:Y は現在の高さに固定した targetFlatPosition を使う(本コードの通り)。
例3:向きが横向き・逆さまに見える
原因:モデルの「前」が Unity 標準の Z+ 前方向と違う。
対処:親子構造で子モデルだけ Rotation を直す(次セクション)。
例4:カメラのほうを向いてしまう
原因:Y を含む direction で LookRotation してしまい、斜め視線になる。
対処:移動は XZ にそろえ、同じ高さ同士の方向ベクトルで回転する(本コードはその形)。
11🧭モデルが横向き! そんなときは親子ワザ
モデルによっては見た目の正面が Unity の前(Z+)と違います。 スクリプトを複雑にするより、親子構造で見た目だけ直すのが管理しやすいです。
- PlayerRoot(ここに ClickMoveController)
- └── Model(見た目のメッシュ。Rotation を微調整)
移動・回転の制御は親の PlayerRoot に任せ、子は見た目専用にします。
12📍+α:クリック地点にキラッとマーク
移動先が視覚的に分かると、RTS やタクティカルRPGっぽい演出になります。実装の考え方の例だけ挙げます。
- 小さな Quad + 半透明マテリアル、または Decal、パーティクルをプレハブ化
- Raycast が成功したら
hit.pointにインスタンス。古いマーカーはDestroyまたは再利用 - Y を少し浮かせると Z-fighting(表面とちらつき)を防げます
13🕺+α:歩きモーションをつなぐ
Animator で Bool パラメータ(例:IsMoving)を用意し、移動中だけ歩き、停止で待機に戻すと体験が良くなります。
// Animator animator; // SerializeField で参照を取る
bool moving = /* hasTarget など */;
animator.SetBool("IsMoving", moving);実プロジェクトでは移動速度に応じて SetFloat でブレンドツリーを動かすことも多いですが、最初は Bool トグルで十分です。
15🏆今日の宝箱(まとめ)
このチュートリアルでは、Unity で画面クリックへ3Dモデルを移動させる流れを学びました。
- ScreenPointToRay でクリック位置から Ray を作る
- Physics.Raycast + LayerMask で地面の点を取得する
- Vector3.MoveTowards で目的地へ近づく
- Quaternion.LookRotation で進行方向を向く
- Quaternion.Slerp でなめらかに回転する
🚀次のステージへ(おすすめ導線)
- クリック位置に移動マーカーを表示する(演出)
- クリック移動に歩きアニメーションを追加する(Animator)
- NavMeshAgent で障害物を避けて移動する
- マウスクリックでオブジェクトを選択する(別レイヤー・UI考慮)
- スマホのタップ操作でキャラクターを移動する(Touch 系)
サイト内の関連:Unity ロードマップ/記事一覧
COMIC MODEキャラ対談で総復習しよ!
ココ先生 🧑🏫 と はじめちゃん 🎒 の漫才トークで、もう一度だけおさらい。
🎮理解チェックミニゲーム(3問)
ボタンを押してから「正解を見る」と、ココ先生が解説してくれるよ。
クイズ
Q1. 画面上のクリック位置から3D空間へRayを飛ばすために使う処理はどれ?
クイズ
Q2. Raycastで地面に当たった位置を取得するために使う値はどれ?
クイズ
Q3. 移動方向を向く回転を作るために使う処理はどれ?
