Unityで移動処理を書いていると、transform.positionを変更しているはずなのに「なぜかオブジェクトが動かない……」という場面があります。
しかも厄介なのは、コードが完全に間違っているとは限らないところです。Inspector上では値が変わっているのに見た目が戻ったり、X方向だけ動かなかったり、Rigidbodyを付けた瞬間に挙動が変わったりします。まるでオブジェクトが反抗期に入ったみたいですね。
この原因を探すときは、まず「Transformを誰が動かしているのか」を確認すると整理しやすくなります。
- 自分のスクリプトが座標を変えている
- Rigidbodyなどの物理演算が座標を制御している
- NavMeshAgentが移動先へ自動で動かしている
- AnimatorやRoot Motionが位置を上書きしている
- Time.timeScaleの影響で移動量が0になっている
Unityでは、Transformの値を直接変更しても、別のコンポーネントが後から座標を上書きすることがあります。つまり、「positionを書いたのに動かない」のではなく、「書いたあとに別の仕組みに戻されている」ケースも多いです。
まずはコードだけを疑うのではなく、Rigidbody、NavMeshAgent、Animator、CharacterController、Time設定、Prefabの参照先を順番に見ていくのが近道です。
- 結論:Transformが動かない時は「誰が座標を支配しているか」を確認する
- Rigidbodyがある場合はFreeze PositionとMovePositionを確認する
- NavMeshAgentがある場合はupdatePositionによる上書きを疑う
- AnimatorやRoot Motionが有効な場合はアニメーションが位置を動かしている可能性がある
- CharacterControllerではTransformよりMoveで移動するのが基本
- Time.timeScaleが0だとdeltaTimeを使った移動は止まる
- 3分で確認できる診断チェックリスト
- よくある誤解・注意点
- まとめ:Transformが動かない時は「上書き・制約・時間停止」の順に見る
- よくある質問(FAQ)
結論:Transformが動かない時は「誰が座標を支配しているか」を確認する
transform.positionを書いているのに動かない時は、最初に「そのオブジェクトの位置を最終的に決めているのは何か」を確認します。
Unityでは、自分のスクリプトだけがTransformを動かしているとは限りません。Rigidbody、NavMeshAgent、Animatorなどが付いていると、それぞれの仕組みが座標を更新することがあります。なので、コードだけをじっと見つめても原因が見つからないことがあるんです。コードとにらめっこしても、たまにUnity側が静かに上書きしています。
最初に確認すべき原因
- RigidbodyのFreeze Positionがオン:特定の軸だけ動かない時に確認します。
- Rigidbody付きオブジェクトをTransformで直接動かしている:物理演算と手動移動がぶつかることがあります。
- NavMeshAgentが座標を上書きしている:敵キャラやAIキャラが元の位置に戻る時に疑います。
- AnimatorのRoot Motionが有効:アニメーション側の移動が優先されることがあります。
- Time.timeScaleが0:
Time.deltaTimeを使った移動量が0になり、動かなくなります。
判断に迷ったら、InspectorでPositionの値を見ながら再生してみてください。ここを見るだけで、原因をかなり絞れます。
| 症状 | 疑う原因 |
|---|---|
| Positionの値がまったく変わらない | コード未実行、参照先ミス、Freeze Position |
| 一瞬変わるけど元に戻る | NavMeshAgent、Animator、別スクリプトの上書き |
| 物理オブジェクトだけ動きが不安定 | RigidbodyとTransform操作の競合 |
| ポーズ中だけ動かない | Time.timeScale、Time.deltaTimeの影響 |
特にRigidbodyを使っている場合は、UpdateとFixedUpdateの違いも関係してきます。物理演算と通常のフレーム更新はタイミングが違うため、移動処理を書く場所によって見え方が変わることがあります。
詳しくは、コチラの記事も参考になります。

まずは「コードが間違っているか」よりも、「他の仕組みがTransformを上書きしていないか」を見る。この考え方に変えるだけで、原因探しがぐっと楽になります。
Rigidbodyがある場合はFreeze PositionとMovePositionを確認する
オブジェクトにRigidbodyが付いている場合、Transformが思った通りに動かない原因は大きく2つあります。1つ目は移動がロックされていること、2つ目は物理演算とTransform操作がぶつかっていることです。
特定の方向だけ動かない時はFreeze Positionを見る
「X方向だけ動かない」「Y方向にジャンプしない」「Z方向へ進まない」というように、特定の軸だけ動かない場合は、RigidbodyのConstraintsを確認してください。
InspectorのRigidbodyには、Freeze Position X、Freeze Position Y、Freeze Position Zという項目があります。ここにチェックが入っていると、その軸方向の移動が制限されます。
- X方向に動かない:
Freeze Position Xを確認する - Y方向に動かない:
Freeze Position Yを確認する - Z方向に動かない:
Freeze Position Zを確認する
スクリプトを何度見直しても原因が分からない時ほど、こういうInspector設定が犯人だったりします。私も昔、コードを30分見続けたあとにチェック1個で解決して、そっとコーヒーを飲みました。
物理オブジェクトを動かす時はTransform操作との競合に注意する
Rigidbody付きのオブジェクトをtransform.positionで直接動かすと、物理演算と手動の座標変更が競合することがあります。たとえば、当たり判定を使いながら毎フレームTransformを書き換えると、ガタついたり、衝突の反応が不自然になったりする場合があります。
物理演算を使って自然に動かしたい場合は、Rigidbody.MovePositionを検討します。これはRigidbodyを通して位置を動かす方法なので、物理処理との相性を取りやすいです。
using UnityEngine;
public class MoveWithRigidbody : MonoBehaviour
{
[SerializeField] private float speed = 3f;
private Rigidbody rb;
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
Vector3 move = new Vector3(1f, 0f, 0f) * speed * Time.fixedDeltaTime;
rb.MovePosition(rb.position + move);
}
}
ポイントは、Rigidbodyを使う移動はFixedUpdateで扱うことが多いという点です。Updateは毎フレーム呼ばれますが、物理演算は固定間隔で処理されるため、処理のタイミングを合わせたほうが安定しやすくなります。
Transformを使ってもよい場面もある
Rigidbodyが付いているからといって、transform.positionを絶対に使ってはいけないわけではありません。使いどころを分けるのが大切です。
- 通常の移動や物理挙動を含む移動:
Rigidbody.MovePositionなどを検討する - リスポーンやワープのような瞬間移動:
transform.positionが使いやすい場合もある - ゲーム開始時の初期配置:Transformで設定して問題ないことが多い
つまり、「ずっと移動させる」のか「一瞬だけ場所を変える」のかで判断すると分かりやすいです。キャラクターや物理オブジェクトを継続的に動かすならRigidbody寄り、配置やワープならTransform寄り、と考えると迷いにくくなります。
Rigidbodyまわりの原因をさらに深く確認したい場合は、コチラの記事もあわせて確認してみてください。
NavMeshAgentがある場合はupdatePositionによる上書きを疑う
敵キャラやNPCにNavMeshAgentを使っている場合、transform.positionを書き換えても思った通りに動かないことがあります。これは、NavMeshAgentが「経路探索用の位置」とTransformの位置を同期しているためです。
特に多いのが、「一瞬だけ移動したように見えるけれど、すぐ元の位置や経路に戻る」という症状です。コードが動いていないというより、NavMeshAgent側の更新があとから入って、Transformの位置を上書きしているイメージですね。
Transformを書き換えても戻る時はupdatePositionを見る
NavMeshAgent.updatePositionが有効になっていると、エージェントのシミュレーション上の位置がTransformに反映されます。通常はこれで問題ありません。敵が目的地へ歩く、プレイヤーを追いかける、といった処理ではNavMeshAgentに任せたほうが自然です。
ただし、スクリプトから直接Transformを動かしたい場面では注意が必要です。
- ノックバックで敵を少し押し戻したい
- 演出で一時的に別の位置へ移動させたい
- ワープや強制移動を入れたい
- カットシーン中だけ手動で位置を制御したい
このような場面でNavMeshAgentが有効なままだと、「せっかく動かしたのに戻される」ことがあります。がんばって押したのに、すん……と定位置に戻るタイプです。
NavMeshAgentに任せるか手動で動かすかを決める
NavMeshAgentを使っているオブジェクトでは、「AIに移動を任せる」のか「一時的に手動で動かす」のかを分けて考えると整理しやすいです。
| やりたいこと | 向いている制御 |
|---|---|
| 目的地まで自動で歩かせる | SetDestinationなどNavMeshAgent中心 |
| 一瞬だけ位置を変える | NavMeshAgentを一時停止、または位置同期を調整 |
| ノックバックさせる | Agentの制御を止める時間を作る、または専用処理に分ける |
| 完全に手動で動かす | updatePositionを確認し、同期方法を自分で管理する |
たとえば、NavMeshAgentで追跡している敵をノックバックさせたい場合、単純にtransform.positionをずらすだけだと、次の更新でAgentが元の経路へ戻そうとすることがあります。その場合は、ノックバック中だけAgentを止める、またはupdatePositionの扱いを見直す必要があります。
updatePositionをfalseにする時の注意点
Transformを直接制御したい場合、agent.updatePosition = false;を使う選択肢があります。これにより、NavMeshAgentのシミュレーション位置が自動でTransformへ反映されにくくなります。
using UnityEngine;
using UnityEngine.AI;
public class AgentManualMove : MonoBehaviour
{
private NavMeshAgent agent;
private void Awake()
{
agent = GetComponent<NavMeshAgent>();
agent.updatePosition = false;
}
private void Update()
{
transform.position += Vector3.forward * Time.deltaTime;
}
}
ただし、updatePositionをオフにすると、NavMeshAgentとTransformの位置をどう合わせるかを自分で考える必要があります。何も考えずにオフにすると、Agentの内部位置と見た目の位置がズレて、経路探索や回避が不自然になる場合があります。
迷った時は、まずNavMeshAgentに移動を任せる設計にできないか考えるのがおすすめです。手動移動が必要な時だけ、Agentの停止や同期設定を部分的に扱うほうが、トラブルを減らしやすいです。
NavMeshAgent自体が動かない、目的地へ向かわない、途中で止まるといった問題もある場合は、コチラの記事も参考にしてみてください。
AnimatorやRoot Motionが有効な場合はアニメーションが位置を動かしている可能性がある
キャラクターにAnimatorが付いている場合、Transformの値をスクリプトで変えても、アニメーション側の処理で位置が上書きされることがあります。
特に確認したいのがApply Root Motionです。Root Motionは、アニメーションクリップに含まれている移動情報を使って、オブジェクト自体を動かす仕組みです。歩く・走る・攻撃しながら前に出る、というような動きをアニメーションに合わせて自然に見せたい時に使われます。
キャラが元の位置に戻る時はRoot Motionを確認する
たとえば、スクリプトでキャラクターを前に動かしているのに、アニメーション再生中だけ位置が戻る場合は、AnimatorがTransformを更新している可能性があります。
- 移動アニメーションを再生すると座標が戻る
- 攻撃モーション中だけキャラの位置がずれる
- InspectorのPositionが一瞬変わるのに、すぐ別の値になる
- 同じコードでも、Animatorを外すと動く
このような症状がある場合は、AnimatorコンポーネントのApply Root Motionを確認してみてください。オンになっていると、アニメーション側の移動が優先される場面があります。
スクリプト移動とRoot Motionは役割を分ける
Transformが動かない原因としてRoot Motionが関係している時は、「スクリプトで動かすのか」「アニメーションで動かすのか」を決めることが大切です。
| やりたいこと | 向いている方法 |
|---|---|
| 入力に合わせて細かく移動したい | スクリプトで移動を制御する |
| 歩幅や攻撃移動をアニメーションに合わせたい | Root Motionを使う |
| 通常移動はスクリプト、攻撃中だけ前進したい | 状態ごとに制御方法を切り替える |
たとえば、プレイヤー操作のキャラクターなら、入力に対してすぐ反応してほしいことが多いです。その場合は、移動自体はスクリプトで行い、Animatorは見た目のアニメーション再生に使う構成が扱いやすいです。
一方で、敵の突進攻撃や必殺技の踏み込みなど、アニメーションの動きに合わせてキャラを動かしたい場合は、Root Motionが便利なこともあります。アニメーションと座標がピタッと合いやすいので、見た目の説得力が出ます。
Apply Root Motionをオフにしても直らない場合
Apply Root MotionをオフにしてもTransformが思った通りに動かない場合は、Animator以外の要因も見てください。たとえば、別スクリプトが毎フレームtransform.positionを書き換えていたり、NavMeshAgentやRigidbodyが同じオブジェクトに付いていたりするケースがあります。
また、親オブジェクトが動いている場合、子オブジェクトの見た目の位置が想定と違って見えることもあります。キャラクター本体、モデル、当たり判定用オブジェクトが親子構造になっている時は、どのTransformを動かしているのかも確認しましょう。
Animatorまわりの挙動も一緒に確認したい場合は、コチラの記事も参考になります。

Root Motionは便利な仕組みですが、スクリプト移動と混ざると原因が見えにくくなります。まずは「このキャラの移動を担当しているのは、スクリプトなのか、アニメーションなのか」をはっきりさせると、迷子になりにくいです。
CharacterControllerではTransformよりMoveで移動するのが基本
CharacterControllerを使っているキャラクターは、通常のTransform操作とは少し考え方が変わります。CharacterControllerは、壁や床との衝突を考慮しながらキャラクターを動かすためのコンポーネントです。
そのため、プレイヤーキャラクターを歩かせるような継続的な移動では、transform.positionを直接変更するよりも、CharacterController.Moveを使うのが基本になります。
壁や床に引っかかる時は移動方法を確認する
CharacterControllerを付けているのにTransformで直接動かしていると、衝突判定や接地判定とズレが出ることがあります。
たとえば、次のような症状が出る場合があります。
- 壁にぶつかった時の挙動が不自然になる
- 床に接している判定が安定しない
- 坂道や段差で思ったように移動できない
- スクリプトでは動かしているのに、当たり判定と見た目がズレる
この場合は、「どこへ移動するか」ではなく「このフレームでどれだけ動かすか」を渡す形にすると整理しやすいです。CharacterControllerでは、この移動量をMoveに渡します。
using UnityEngine;
public class PlayerMoveController : MonoBehaviour
{
[SerializeField] private float speed = 3f;
private CharacterController controller;
private void Awake()
{
controller = GetComponent<CharacterController>();
}
private void Update()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 move = new Vector3(horizontal, 0f, vertical);
controller.Move(move * speed * Time.deltaTime);
}
}
transform.position = 目的地;のように座標を直接指定するのではなく、controller.Move(移動量);で「今どれだけ動くか」を渡すのがポイントです。ここを混同すると、「positionを変えているのに思った通りに動かない」と感じやすくなります。
Transformを使う場面もある
CharacterControllerを使っている場合でも、Transform操作がまったく不要になるわけではありません。たとえば、リスポーンやワープのように、キャラクターを一瞬で別の場所へ移したい時はtransform.positionを使う場面があります。
| やりたいこと | 使いやすい方法 |
|---|---|
| プレイヤーを歩かせる | CharacterController.Move |
| 壁や床との衝突を考慮する | CharacterController.Move |
| チェックポイントへ戻す | transform.position |
| 別エリアへワープさせる | transform.position |
判断に迷ったら、「普段の移動か、一瞬の位置変更か」で分けると分かりやすいです。普段の移動はCharacterController、ワープや初期配置はTransform、という考え方ですね。
Rigidbodyとは役割が違う
CharacterControllerとRigidbodyは、どちらもキャラクター移動で使われますが、役割は同じではありません。
CharacterControllerは、プレイヤー操作のように「自分で移動を管理したいキャラクター」に向いています。一方、Rigidbodyは物理演算で押されたり、転がったり、力を加えられたりする動きに向いています。
- 自分で歩行やジャンプを制御したい:CharacterController
- 力を加えて物理的に動かしたい:Rigidbody
- 敵やNPCを目的地へ歩かせたい:NavMeshAgent

この3つを同じ感覚で扱うと、Transformが動かない原因がかなり見えにくくなります。キャラクターが何によって動く設計なのかを先に決めておくと、移動処理の迷子を防ぎやすいです。
Time.timeScaleが0だとdeltaTimeを使った移動は止まる
コードも参照先も合っているのに、あるタイミングから急にTransformが動かなくなる場合は、Time.timeScaleを確認してみてください。
Time.timeScaleは、ゲーム全体の時間の進み方を調整する値です。通常は1ですが、ポーズ画面や一時停止処理で0にすると、ゲーム内の時間が止まったような状態になります。
ポーズ中だけ動かない時はdeltaTimeを見る
よくあるのが、移動処理にTime.deltaTimeを使っているケースです。
transform.position += Vector3.right * speed * Time.deltaTime;
この書き方自体はよく使われます。フレームレートの違いによる移動量のズレを減らせるので、通常の移動ではむしろ自然です。
ただし、Time.timeScaleが0になっていると、Time.deltaTimeを使った移動量も実質的に0になります。つまり、計算式としては動かしているつもりでも、最終的な移動量が0になっているわけです。
- ポーズ画面を開いたら動かなくなった
- ゲームオーバー後に再開しても動かない
- メニューを閉じたのにキャラクターが止まったまま
- フェード演出やUIだけ動かしたいのに止まる
このような症状がある場合は、どこかでTime.timeScale = 0;にして、その後1へ戻し忘れていないか確認しましょう。地味ですが、かなりよくある落とし穴です。
ポーズ中も動かしたい処理はunscaledDeltaTimeを使う
ポーズ中でも動かしたい処理には、Time.unscaledDeltaTimeを使う方法があります。これはtimeScaleの影響を受けにくい時間です。
transform.position += Vector3.right * speed * Time.unscaledDeltaTime;
ただし、何でもunscaledDeltaTimeにすればよいわけではありません。ゲーム世界のキャラクターや敵までポーズ中に動いてしまうと、「一時停止とは……?」という状態になります。
| 処理の種類 | 使いやすい時間 |
|---|---|
| プレイヤーや敵の通常移動 | Time.deltaTime |
| ゲーム内の弾やギミック | Time.deltaTime |
| ポーズ画面のUI演出 | Time.unscaledDeltaTime |
| フェードイン・フェードアウト | 状況に応じてTime.unscaledDeltaTime |
timeScaleを戻し忘れていないか確認する
ポーズ処理を作る時は、止める処理だけでなく、戻す処理もセットで確認しておくと安心です。
public void PauseGame()
{
Time.timeScale = 0f;
}
public void ResumeGame()
{
Time.timeScale = 1f;
}
ゲーム再開時にTime.timeScaleを1へ戻していないと、Transformだけでなく、アニメーション、物理演算、コルーチンの待機処理などにも影響が出る場合があります。原因が広がるので、かなりややこしくなります。
ポーズ機能を作ってから「急に動かなくなった」と感じたら、まずTime.timeScaleの現在値をログで確認してみるのがおすすめです。
Debug.Log(Time.timeScale);
ポーズ処理や時間制御について詳しく確認したい場合は、コチラの記事も参考になります。
また、ポーズ状態やゲーム進行状態、設定値などを保存したい場合は、セーブ管理用アセットを使うと実装を整理しやすくなります。
Easy Save
✅アセットストアでチェックする
3分で確認できる診断チェックリスト
Transformが動かない原因は、いきなりコード全体を見直すよりも、順番を決めて確認したほうが早く見つかります。特に初心者のうちは、「どこから疑えばいいの?」で時間を使いがちなので、まずは下の順番でチェックしてみてください。
動かしたいオブジェクトはシーン上のインスタンスか
まず確認したいのは、操作している対象が本当にシーン上のオブジェクトかどうかです。
ProjectウィンドウにあるPrefabアセットを参照しているだけだと、Hierarchy上に存在する実体は動きません。Prefabはあくまで「元データ」のようなものなので、実際に動かすにはシーン上に配置されたオブジェクト、またはInstantiateで生成したインスタンスを操作する必要があります。
GameObject obj = Instantiate(prefab);
obj.transform.position = new Vector3(0f, 2f, 0f);
このように、Instantiateした戻り値を変数に入れて、その変数のTransformを動かすと分かりやすいです。
Consoleにエラーが出ていないか
次にConsoleを確認します。NullReferenceExceptionなどのエラーが出ていると、移動処理まで到達していない場合があります。
コード上ではtransform.positionを書いていても、その前の行でエラーが出て処理が止まっていれば、当然オブジェクトは動きません。まず赤いエラーが出ていないかを見て、出ている場合は先にそこを直しましょう。
エラー原因の整理に迷う場合は、コチラの記事も参考になります。
Inspector上でPositionの値は変わっているか
再生中にInspectorを開き、対象オブジェクトのPositionを見てください。ここは原因を分ける大事な分岐点です。
- Positionの値が変わらない:コード未実行、参照先ミス、Freeze Positionなどを疑う
- Positionの値は変わるが戻る:Animator、NavMeshAgent、別スクリプトの上書きを疑う
- Positionの値は変わるが見た目が動かない:親子関係、カメラ、表示オブジェクトの参照違いを疑う
私はこの確認を「犯人の足あとを見る作業」だと思っています。値が動いているかどうかを見るだけで、原因の方向がかなり絞れます。
RigidbodyのConstraintsを確認する
Rigidbodyが付いている場合は、ConstraintsのFreeze Positionを見ます。特定の軸だけ動かない時は、ほぼ最初に確認してよい項目です。
- X方向に動かないなら
Freeze Position X - Y方向に動かないなら
Freeze Position Y - Z方向に動かないなら
Freeze Position Z
コードが合っていても、Inspector側でロックされていれば動きません。スクリプトより設定のほうが強く見える場面ですね。
NavMeshAgentやAnimatorが付いていないか確認する
Hierarchyで対象オブジェクトを選び、NavMeshAgentやAnimatorが付いていないか確認します。
NavMeshAgentが付いている場合は、AgentがTransformを同期している可能性があります。Animatorが付いている場合は、Root Motionやアニメーション側の制御で位置が変わっているかもしれません。
特に「一瞬だけ動いて戻る」症状なら、この2つはかなり有力候補です。
Time.timeScaleが0になっていないか確認する
ポーズ画面やゲームオーバー処理を作ったあとに動かなくなった場合は、Time.timeScaleをログで確認します。
Debug.Log(Time.timeScale);
0のままだと、Time.deltaTimeを使った移動は止まります。再開ボタンを押した時にTime.timeScale = 1f;へ戻しているかも見ておきましょう。
別スクリプトが毎フレーム上書きしていないか
最後に、同じオブジェクトのTransformを別スクリプトでも変更していないか確認します。
たとえば、PlayerMove.csで右へ動かしているのに、FollowTarget.csで毎フレーム別の位置へ戻していると、動いていないように見えます。複数のスクリプトが同じTransformを触っている時は、「最後に書いた処理」が見た目に反映されやすいです。
迷った時は、プロジェクト内検索で.positionやtransform.positionを探してみるのもおすすめです。思わぬ場所で座標を書き換えているコードが見つかることがあります。

ここまで確認すると、Transformが動かない原因はかなり絞れます。大事なのは、感覚で直そうとするより、Positionの値が変わっているか、誰が座標を上書きしているかを順番に見ることです。
よくある誤解・注意点
Transformが動かない問題は、原因が1つに見えて、実は複数の仕組みが重なっていることがあります。ここでは、初心者が特に混同しやすいポイントを整理しておきます。
Transformで動かないならコードが間違っているとは限らない
transform.positionを書いているのに動かないと、まずコードミスを疑いたくなりますよね。もちろんスペルミスや参照ミスもありますが、Unityではコードが正しく実行されていても、別のコンポーネントが座標を上書きすることがあります。
たとえば、NavMeshAgentが経路探索で位置を更新していたり、AnimatorのRoot Motionがキャラクターの位置を動かしていたりするケースです。この場合、スクリプトで一度positionを変えても、その後の更新で別の値に戻されます。
そのため、「動かない=コードが間違っている」とすぐ決めつけず、InspectorでPositionの値が変化しているかを先に見るのがおすすめです。
Rigidbody付きでもTransformを絶対に使ってはいけないわけではない
Rigidbodyが付いているオブジェクトは、物理演算を通して動かすのが基本です。継続的な移動や衝突を含む移動では、Rigidbody.MovePositionや速度、力を使った方法のほうが安定しやすいです。
ただし、transform.positionが完全にNGというわけではありません。たとえば、ゲーム開始時の初期位置設定、リスポーン、ワープ、ステージ切り替え時の配置変更などでは、Transformで直接位置を変える場面もあります。
- 毎フレームの移動:Rigidbody系の移動方法を検討する
- 一瞬だけ位置を変える処理:Transform操作が使いやすい場合もある
- 物理挙動を重視する処理:Transformの直接変更は慎重に扱う
大事なのは、「何となくTransformで動かす」のではなく、物理演算を使いたいのか、単に位置を変えたいだけなのかを分けることです。
原因は1つとは限らない
Transformが動かない原因は、1つだけとは限りません。RigidbodyのFreeze Positionが入っていて、さらにAnimatorも位置を上書きしている、というような合わせ技もあります。Unity、たまにコンボを決めてきます。
たとえば、次のような組み合わせは原因特定が難しくなりやすいです。
- RigidbodyとAnimatorが同じオブジェクトに付いている
- NavMeshAgentで移動しながら、別スクリプトでもpositionを変更している
- 親オブジェクトと子オブジェクトの両方を別々に動かしている
- ポーズ処理でtimeScaleを0にしたまま、移動処理を確認している
原因が見つからない時は、一度コンポーネントを減らしたシンプルな状態で確認すると切り分けやすいです。たとえばAnimatorを一時的に無効化する、NavMeshAgentを止める、別スクリプトを外してみる、といった確認方法があります。
2Dと3Dでは使うコンポーネントが違う
2Dゲームを作っている場合は、RigidbodyではなくRigidbody2D、ColliderではなくCollider2Dを使います。名前が似ているので混同しやすいですが、2D物理と3D物理は別の仕組みです。
たとえば、2DキャラクターにRigidbody2Dを付けているのに、3D用のRigidbodyの情報を見て原因を探していると、なかなか解決にたどり着けません。
| 用途 | 3D | 2D |
|---|---|---|
| 物理演算 | Rigidbody | Rigidbody2D |
| 当たり判定 | Collider | Collider2D |
| 移動処理 | Vector3を使うことが多い | Vector2を使うことが多い |
2Dの記事やコードを参考にしているのか、3Dの記事やコードを参考にしているのかも確認しておくと、余計な混乱を避けやすくなります。
Prefabを動かしてもシーン上のオブジェクトは動かない
ProjectウィンドウにあるPrefabアセットと、Hierarchy上にあるオブジェクトは別物です。Prefabは元データ、Hierarchy上のオブジェクトは実際にシーンで動くインスタンスだと考えると分かりやすいです。
スクリプトでPrefabアセットそのものを参照してpositionを変更しても、すでにシーン上に出ている別のインスタンスが動くとは限りません。Instantiateで生成した場合は、生成された戻り値を変数に入れて、そのTransformを操作しましょう。
GameObject enemy = Instantiate(enemyPrefab);
enemy.transform.position = spawnPoint.position;

「Prefabを指定したはずなのに動かない」と感じた時は、いま動かしているのが元データなのか、シーン上の実体なのかを確認してみてください。ここを間違えると、コードは動いているのに画面では何も起きない、という状態になりやすいです。
まとめ:Transformが動かない時は「上書き・制約・時間停止」の順に見る
Unityでtransform.positionを書いているのに動かない時は、コードだけを疑うよりも、まず「別の仕組みが座標を上書きしていないか」を見ると原因を絞りやすいです。
特に、Rigidbody、NavMeshAgent、Animator、CharacterController、Time.timeScaleは、Transformの動きに大きく関係します。どれもUnityではよく使う機能なので、正常に働いている結果として「Transformが思った通りに動かない」ように見えることがあります。
確認する順番
- Inspectorで
Positionの値が変わっているか確認する - Rigidbodyの
Freeze Positionで移動がロックされていないか見る - Rigidbody付きなら、
transform.positionで毎フレーム動かしていないか確認する - NavMeshAgentやAnimatorが位置を上書きしていないか見る
Time.timeScaleが0になっていないか確認する- Prefabアセットではなく、シーン上のインスタンスを操作しているか確認する
- 別スクリプトが毎フレームpositionを書き換えていないか探す
私が原因を探す時は、まず再生中のInspectorでPositionを見ます。値がまったく変わらないなら、コード未実行や参照先ミス、Freeze Positionを疑います。反対に、値が一瞬変わって戻るなら、NavMeshAgent、Animator、別スクリプトの上書きを疑います。
この分け方を覚えておくと、闇雲にコードを書き換えなくて済みます。エラー原因探しで一番つらいのは、直しているつもりで別の場所を壊してしまうことなので、まずは症状を観察するのがおすすめです。
再発を防ぐ考え方
Transformのトラブルを減らすには、「このオブジェクトは何で動かすのか」を先に決めておくと楽です。
- 単純な位置変更なら
Transform - 物理演算や衝突を重視するなら
Rigidbody - AIで目的地へ移動させるなら
NavMeshAgent - キャラクター操作を自前で管理するなら
CharacterController - アニメーションの歩幅や踏み込みを使うなら
Root Motion
複数の仕組みを混ぜる場合は、「通常移動はNavMeshAgent、ノックバック中だけ手動制御」のように、制御するタイミングを分けると整理しやすくなります。
Transformが動かない時は、焦ってコードを全部書き換える前に、座標を決めている担当者を探してみてください。Unityの中で「誰が最後にpositionを書いたのか」を見つける感覚です。ここが分かると、原因探しがぐっと現実的になります。
よくある質問(FAQ)
- QTransform.positionを使うのは間違いですか?
- A
Transform.positionを使うこと自体は間違いではありません。単純にオブジェクトの位置を変えたい時や、初期位置の設定、ワープ、リスポーンなどではよく使います。ただし、Rigidbody、NavMeshAgent、Animatorなどが付いているオブジェクトでは注意が必要です。これらのコンポーネントは、それぞれの仕組みで位置を更新することがあります。そのため、
transform.positionで動かしても、あとから別の処理に上書きされる場合があります。- 単純な配置変更:
transform.positionで扱いやすい - 物理演算を使った移動:
Rigidbody.MovePositionなどを検討する - AI移動:
NavMeshAgentに任せる - アニメーション主導の移動:Root Motionの設定を確認する
「Transformが悪い」というより、「そのオブジェクトの移動担当を1つに決める」ことが大切です。担当者が多すぎると、Unity内で静かな座標会議が始まってしまいます。
- 単純な配置変更:
- QPositionの値は変わっているのに画面上で動かないのはなぜですか?
- A
Inspector上で
Positionの値が変わっているのに画面では動いていないように見える場合、Transform以外の要素が関係している可能性があります。たとえば、カメラが対象を映していなかったり、親オブジェクトの影響で見た目の位置が分かりにくくなっていたり、実際に動かしているオブジェクトと表示されているモデルが別になっているケースがあります。
- カメラが対象を追っていない
- 親オブジェクトが別方向に動いている
- 子オブジェクトではなく親だけを動かしている
- 見た目のモデルと当たり判定用オブジェクトが分かれている
- RendererやLayer設定の影響で見え方が変わっている
この場合は、Hierarchyでどのオブジェクトを選んでいるかを確認しながら、Sceneビューで実際の位置を見てみると原因を見つけやすいです。Gameビューだけで判断すると、カメラや表示設定に惑わされることがあります。
- QUpdateとFixedUpdateのどちらで移動すればいいですか?
- A
Transformを直接動かす簡単な移動なら、
Updateで扱うことが多いです。たとえば、キー入力に応じてオブジェクトを移動させるような処理ですね。一方で、Rigidbodyを使った物理移動では、
FixedUpdateを意識する場面が増えます。物理演算は固定間隔で処理されるため、Rigidbodyの移動処理を通常のUpdateに書くと、環境によって動きが不安定に見えることがあります。処理の内容 使いやすい更新タイミング 入力取得 UpdateTransform中心の簡単な移動 UpdateRigidbodyを使う物理移動 FixedUpdateUIアニメーション Updateただし、入力を
FixedUpdateだけで取ると、タイミングによって入力を取りこぼすことがあります。よくある形としては、入力はUpdateで受け取り、物理的な移動はFixedUpdateで反映する、という分け方です。Transformが動かない原因を探す時は、「どの関数に書くべきか」だけでなく、「その移動は物理演算を使う移動なのか」を一緒に考えると判断しやすくなります。













※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。
※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。