【Unity初心者】Cubeを動かす・ジャンプさせる|業務プログラマがハマった物理挙動の3つのワナ)

UnityでCubeを移動・ジャンプさせるチュートリアル記事のアイキャッチ画像。初心者向けの操作解説をイメージ

私は33年間、業務システムを書いてきました。COBOLから始まって、VB、C#、ASP.NET……お客様の会社の請求や在庫を支える、地味だけど「絶対に間違えられない」プログラムです。

そんな私が、憧れだったUnityで初めてCubeを動かしたとき。他の入門記事には書かれていない、3つのつまずきに出くわしました。

動くコードを載せた記事は、たくさんあります。この記事もまず、Cubeを移動・ジャンプさせるコードを一通り作ります。でもそれだけでは終わりません。業務プログラマの目で見たときに「ん?」と引っかかった箇所と、2026年のUnity 6で実際に動かし直した検証結果を、正直に足していきます。

もしあなたも業務システムやWindowsアプリを書いてきた人なら、きっと同じ場所で立ち止まるはずです。一緒に見ていきましょう。

目次

UnityプロジェクトとCubeの準備

Unityでオブジェクトを動かすために、まずはプロジェクトを作成し、シーンにCubeを配置していきましょう!

シンプルなステップなので、初めての方でも安心して進められます。

新しいプロジェクトを作成する

Unity Hubで3Dプロジェクトを新規作成する画面

まずはUnity Hubを開き、新しいプロジェクトを作成します。

  1. Unity Hubを起動します。
  2. 「新しいプロジェクト」をクリックします。
  3. テンプレートは「3D(Built-In Render Pipeline)Core」を選択します。
  4. プロジェクト名は分かりやすく「CubeMoveJump」としましょう。
  5. 保存場所を指定して「作成」を押します。

これで、移動・ジャンプを試すためのシンプルな3D環境が整いました!

Plane(地面)オブジェクトを配置する

UnityエディターでPlane(平面)を追加する画像

プロジェクトが立ち上がったら、まずシーンに舞台となるPlane(地面)を配置していきます。

  1. Hierarchy(ヒエラルキー)ウィンドウ上で右クリック
  2. 【3D Object】→【Plane】を選択します
  3. シーン中央にPlane(地面)が配置されます
    ※もし中央に配置されていない場合、インスペクターのTransformPositionを全て0にする

Cubeオブジェクトを配置する

UnityのHierarchyウィンドウからCubeオブジェクトを作成する手順

プロジェクトが立ち上がったら、次はシーンにCubeオブジェクトを配置していきます。

  1. Hierarchy(ヒエラルキー)ウィンドウ上で右クリック
  2. 【3D Object】→【Cube】を選択します
  3. シーン中央に白いCubeが配置されます

これが、今回操作の対象になるオブジェクトです。

CubeオブジェクトがPlane(地面)に埋もれている場合は、CubeオブジェクトのTransformPositionYを0.5ほど上にあげるなど調整してみて下さい

Rigidbodyコンポーネントを追加する

UnityエディターでCubeにRigidbodyコンポーネントを追加する操作

次に、Cubeに「物理挙動」を持たせるためのコンポーネントを追加します。

  1. HierarchyでCubeを選択
  2. Inspector(インスペクター)ウィンドウで「Add Component」をクリック
  3. 「Rigidbody」と検索し、追加します

これでCubeに重力や物理演算が働くようになりました!

Rigidbodyがあることで、ジャンプや落下など「現実っぽい動き」ができるようになります。

Rigidbodyを追加するだけで、Unityは自動的に重力や衝突などの物理演算を有効にしてくれます。

Rigidbodyとは、オブジェクトに“重さや運動”の性質を持たせるためのコンポーネントです。
Unityの物理演算(重力・衝突・跳ね返りなど)を使うには、まずこのRigidbodyを追加する必要があります。

Cubeを移動させる(WASDキー操作)

UnityでCubeをWASDキーで操作している様子を表すイメージ図。物理挙動での移動制御を表現。

Cubeを前後左右に動かせるように、
WASDキーの入力を受け取り、Rigidbodyを使って物理的に動かすスクリプトを作成します。

これができると、ゲームキャラクターの**「基本の移動操作」**が自分で制御できるようになります!

移動用スクリプトを作成する

UnityエディターでCube用のC#スクリプトを作成する操作画面
  1. Assets フォルダで右クリック → Create > C# Script
  2. スクリプト名を CubeMover にします
  3. Cube オブジェクトを選択し、作成したスクリプトをドラッグ&ドロップでアタッチします

スクリプトがCubeに紐づいた状態になります!

UnityエディターでCubeオブジェクトにC#スクリプトをアタッチする

WASD入力を受け取る仕組みを理解しよう

CubeMoverファイルを開き、以下のようなコードを記述します。

using UnityEngine;

public class CubeMover : MonoBehaviour
{
    public float moveSpeed = 5f;
    private Rigidbody rb;

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    private void FixedUpdate()
    {
        float moveX = Input.GetAxis("Horizontal");
        float moveZ = Input.GetAxis("Vertical");

        Vector3 move = new Vector3(moveX, 0f, moveZ) * moveSpeed;
        rb.velocity = new Vector3(move.x, rb.velocity.y, move.z);
    }
}

解説

  • Input.GetAxis("Horizontal") → A・Dキー(または←→キー)
  • Input.GetAxis("Vertical") → W・Sキー(または↑↓キー)
  • FixedUpdate() → Rigidbodyを扱うときに使うフレーム制御関数

WASDの入力をリアルタイムに取得し、Rigidbodyの速度として反映させます。

Cubeオブジェクトが回転してしまうときは…

UnityエディターでFreeze Rotationを設定する

Rigidbodyを使った移動では、オブジェクトが物理的に回転してしまうことがあります。
それが気になる場合は、Cubeのインスペクターで Constrains→Freeze Rotation のX/Zにチェックを入れておくと、地面の上をまっすぐ動かすことができます。

今回はCubeオブジェクトの物理さしさを生かすため、回転はあえてそのままでもOKです。
お好みに合わせて設定してみてください。

つまずき①|FixedUpdate って、何の時計で動いてるの?

さっそくコードを書いていきますが、その前に。移動スクリプトの中に、こんな見慣れないメソッドが出てきます。

private void FixedUpdate()
{
    // ここに移動の処理を書く
}

Start はまだわかります。「最初に一回だけ呼ばれる」——業務でいう初期化処理ですね。でも FixedUpdate って、いったい誰が、いつ呼んでいるんでしょうか?

私はここで、最初の大きなつまずきに出くわしました。

業務プログラムは「呼ばれてから動く」

33年間、私が書いてきた業務システムやWindowsアプリは、基本的にぜんぶイベント駆動でした。

ボタンが押される → Button_Click が呼ばれる → 処理する → 終わり。
画面が開かれる → Form_Load が呼ばれる → 初期表示する → 終わり。

「何かが起きたら、それに反応する」。これが体に染みついた基本形です。逆に言えば、何も起きなければ、プログラムは何もしません。ボタンを押さないのに Button_Click が勝手に走り出したら、それはもう不具合です。

Unityは「誰も呼ばないのに、ずっと動いている」

ところがUnityは、まるで逆でした。

Update() というメソッドは、誰もクリックしていないのに、あなたが何もしていないのに、勝手に毎秒約60回、走り続けています。ゲームが起動している間ずっと、休みなく。

初めてこれを知ったとき、正直ぞわっとしました。業務の感覚では「暴走」に見えるからです。でも、考えてみれば当たり前でした。ゲームの画面は、キャラが動き、敵が迫り、時間が流れ続けている。世界そのものが、止まらずに動き続けている。だから毎フレーム、世界を少しずつ描き直す必要がある。その「毎フレームの心臓の鼓動」が Update() なんです。

業務アプリが「お客さんが窓口に来たら対応する銀行の受付」だとしたら、Unityは「お客さんがいてもいなくても回り続ける、遊園地のメリーゴーラウンド」。この違いに気づいたとき、Unityがすっと腑に落ちました。

業務プログラムとUnityの動き方の違い 業務プログラムはイベントで呼ばれてから動く。Unityは誰も呼ばなくてもUpdateが毎フレーム自動で動き続ける、という対比図。 業務プログラム 呼ばれてから動く ボタンが押される Button_Click() 処理して終わり Unity 呼ばれなくても動く Update() 誰も呼ばないのに 毎秒 約60回 自動実行 ↻ ずっと繰り返す

で、UpdateFixedUpdate、時計が2つある

やっかいなのは、その「勝手に動く時計」が、Unityには2種類あることです。

メソッド呼ばれるタイミング何に使う
Update()毎フレーム(PCの性能で回数が変わる)キー入力の受付、見た目の更新
FixedUpdate()一定の時間ごと(性能に関係なく一定)Rigidbodyを使った物理の処理

なぜ分かれているのか。ここに、業務プログラマがハマる罠があります。

Update() は、PCが速ければ毎秒120回、遅ければ毎秒30回、と回数がバラバラになります。画面を描くだけならそれでいい。でも、これで物理演算(重力や速度の計算)をやると、速いPCと遅いPCで、キャラの動く距離が変わってしまうんです。同じゲームなのに、環境によって挙動が変わる。

業務システムでこれをやったら大事故です。「このPCだと合計金額が合うのに、別のPCだと合わない」——考えただけで冷や汗が出ます。Unityはこの問題を避けるために、物理の計算だけは、性能に左右されない一定リズムの FixedUpdate() に隔離しているわけです。

だから、この記事の移動処理はこうなっています。

  • キー入力を「受け付ける」のは、反応の速さが大事だから → Update() 寄りの発想
  • Rigidbodyで「実際に動かす」のは、環境で挙動が変わっては困るから → FixedUpdate()

「入力は素早く、物理は正確に」。時計を使い分ける理由が腑に落ちると、FixedUpdate はもう怖くありません。

ちなみに私は、この「毎フレーム動く」感覚を、以前Phaserでブロック崩しを作ったときに一度つかんでいました。あのとき覚えた update の考え方は、エンジンが変わってもちゃんと生きています。畑が違っても、一度わかった原理は無駄にならない——これは、遅れてゲーム開発を始めた私にとって、地味に嬉しい発見でした。

つまずき②|このコード、2026年のUnity 6だと勝手に書き換わりました

移動のコードを、もう一度見てください。

rb.velocity = new Vector3(move.x, rb.velocity.y, move.z);

この記事のベースは、私がUnity 2022.3で書いたものです。当時、このコードは何の問題もなく、これが正解でした。

ところが2026年、私はこのプロジェクトをUnity 6で開き直しました。そして移動処理を見て、思わず二度見しました。自分では一文字も触っていないのに、コードがこう変わっていたんです。

rb.linearVelocity = new Vector3(move.x, rb.linearVelocity.y, move.z);

velocitylinearVelocity に。誰が書き換えたのか。私は書いていません。

「旧形式です」——戻してみて、理由がわかった

気になったので、試しに元の rb.velocity に手で戻してみました。すると、Visual Studioがすかさず警告を出しました。

Unity 6(正確にはUnity 2023.3以降)で、Rigidbody.velocity は非推奨になりました。今後は linearVelocity(線形速度)を使ってください、という案内です。角速度 angularVelocity と名前の対を揃えるための変更ですね。

つまり、こういうことでした。

  • 2022年に書いた rb.velocity は、当時は正しかった
  • Unity 6でプロジェクトを開いたとき、Unityが「これは古い書き方だから直しておくよ」と、自動で linearVelocity に書き換えた
  • 警告文の末尾にあった (UnityUpgradable) -> linearVelocity が、その「自動で直していい印」だった

フレームワークが、勝手に私のコードを直す

ここで、また業務畑の私が固まりました。

フレームワークが、開発者に断りなくソースコードを書き換える。 業務システムの世界では、まず起こりません。私たちの現場では、ソースは一行たりとも「誰が・いつ・なぜ変えたか」を記録します。勝手に書き換わるなんて、恐怖でしかない。もし基盤が黙ってコードを直したら、その日は原因調査で一日が終わります。

でもUnityのこれは、恐怖ではなく——正直、ありがたい親切でした。

ゲームエンジンは、バージョンが上がると古い書き方がどんどん非推奨になります。その全部を手で追いかけるのは大変です。Unityは「よく使われる古いAPIは、開こうとした時に自動で新しい書き方へ直す」という仕組み(API Updater)を持っていて、面倒を肩代わりしてくれる。業務システムの「絶対に勝手に変えるな」という文化とは真逆ですが、変化の速いゲーム開発では、この割り切りのほうが合っているんだと思います。ここでもまた、二つの世界の価値観の違いを感じました。

で、私はどっちを書けばいいの?

あなたの環境しだいで、答えが変わります。

あなたのUnity書くべきコード
Unity 2022.3 など(〜2023.2)rb.velocitylinearVelocity はまだ無い)
Unity 6(2023.3〜)rb.linearVelocityvelocity は非推奨警告が出る)

新しくこれから作るなら、Unity 6を使っている方が多いはずなので、linearVelocity で書いておけば安心です。もし古い教材や記事のコードをコピーして「警告が出た」「動かない」と焦ったら、まずこの名前の違いを疑ってみてください。

そしてこれは、入門記事を読むとき全体に言えることです。サンプルコードには「賞味期限」があります。 書かれた当時のバージョンでは正しくても、数年経つと非推奨になっていることがある。

だから私はこの記事で、あえて「いつのバージョンで書いたか」を明記しています。あなたが2028年にこれを読んでいたら——そのときはまた、別のAPIが変わっているかもしれません。

Cubeオブジェクトをジャンプさせる(スペースキー)

Cubeをジャンプしようとしているイメージ図。

キャラクターのジャンプは、ゲームらしい操作のひとつです。
ここでは Cube にジャンプ機能を追加して、スペースキーで「ぴょんっ」と跳ねる動きを実装してみましょう!

スクリプトにジャンプ処理を追加する

前回作成した CubeMover.cs に、ジャンプのための変数と処理を追記します。

public float jumpForce = 5f;
private bool isGrounded = true;

そして Update() メソッド内に以下の処理を追加します

if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
    rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
    isGrounded = false;
}

このコードではスペースキー押下と「地面にいるとき」にジャンプできるようにしています。

地面に触れたら再びジャンプできるようにする

ジャンプのあとに再びジャンプができるように、
OnCollisionEnter() を使って「何かに触れたら着地したとみなす」処理を追加します。

private void OnCollisionEnter(Collision collision)
{
    isGrounded = true;
}

ここではすべてのオブジェクトとの接触で isGrounded = true にしていますが、
あとで「地面だけに限定する」処理も追加可能です。今回は省略します。

完成したジャンプコードの全体像

最終的に、CubeMover.cs は以下のようになります。

using UnityEngine;

public class CubeMover : MonoBehaviour
{
    public float moveSpeed = 5f;
    private Rigidbody rb;

    public float jumpForce = 5f;
    private bool isGrounded=true;

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
    }
    private void Update()
    {
        // ジャンプ
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
            isGrounded = false;
        }
    }
    private void FixedUpdate()
    {
        float moveX = Input.GetAxis("Horizontal");
        float moveZ = Input.GetAxis("Vertical");

        Vector3 move = new Vector3(moveX, 0f, moveZ) * moveSpeed;
        rb.velocity = new Vector3(move.x, rb.velocity.y, move.z);
    }
    private void OnCollisionEnter(Collision collision)
    {
        // 地面に触れたら再ジャンプ可能にする(Planeなど)
        isGrounded = true;
    }

}

つまずき③|「今回は省略します」に、私はゾッとした

ジャンプのコードは、これで一応動きます。でも私は、この部分を書いた瞬間に手が止まりました。

private void OnCollisionEnter(Collision collision)
{
    // 地面に触れたら再ジャンプ可能にする
    isGrounded = true;
}

もう一度、コードをよく見てください。このメソッドは「何かに触れたらisGroundedtrue にしています。何か、です。地面とは書いていません。

つまり——空中でジャンプ中に、横の壁にちょっと触れただけで、また跳べてしまうんです。壁を蹴って二段ジャンプ、三段ジャンプ。マリオならアクロバティックですが、たいていのゲームでは「バグ」と呼ばれる動きです。

入門記事では、ここをこう書いて済ませることがよくあります。「今回は省略します」と。実は、この記事のベースにした私自身の下書きにも、そう書いてありました。

でも、この「省略します」に、業務畑の私はゾッとしたんです。

なぜ業務プログラマはここで固まるのか

業務システムの世界で、「条件が漏れてるけど、まあ動くから今回はいいか」は、絶対にやりません

たとえば請求書の合計金額を計算するコード。「特定の取引先だけ、消費税の丸め方が違う」という条件を一つ書き忘れたら、請求額が数円ずれます。たった数円。でもそれが100社分、毎月積み重なって、決算のときに「帳簿が合わない」と大騒ぎになる。私はそういう現場を、何度も見てきました。

だから業務プログラマの体には、「例外条件を書き漏らす気持ち悪さ」が染みついています。この OnCollisionEnter を見た瞬間、頭の中で赤ペンが走りました。「これ、レビューなら差し戻しだぞ」と。

isGrounded判定の修正前と修正後 修正前はどの衝突でもisGroundedがtrueになり壁でも跳べてしまう。修正後はCompareTagで地面だけをtrueにするため壁では跳べない、という対比図。 修正前 何に触れても再ジャンプできてしまう 地面 天井 isGrounded = true になる → 壁でも跳べる(バグ) 修正後 地面に触れたときだけ true 地面 天井 CompareTag(“Ground”) で判定 → 壁では跳べない

業務の「気持ち悪さ」で、ちゃんと直してみる

というわけで、直しましょう。やることはシンプルで、「触れた相手が地面かどうか」を確認してから isGrounded を戻すだけです。

まず、地面役のPlaneに「Ground」というタグを付けます。

  1. HierarchyでPlaneを選択します
  2. Inspectorの一番上、名前の下にある「Tag」→「Add Tag…」をクリックします
  3. 「+」で Ground というタグを新規作成します
  4. もう一度Planeを選び、Tagのプルダウンから Ground を選びます

そして、コードをこう書き換えます。

private void OnCollisionEnter(Collision collision)
{
    // ★「地面」に触れたときだけ、再ジャンプ可能にする
    if (collision.gameObject.CompareTag("Ground"))
    {
        isGrounded = true;
    }
}

CompareTag("Ground") で、「今ぶつかった相手はGroundタグを持っているか?」を確認しています。壁に触れても、その壁がGroundタグでなければ isGroundedtrue になりません。これで、空中で壁を蹴って跳ぶことはできなくなりました。

「省略」が正しいときもある、という話

ここまで書いておいて、ちゃぶ台をひっくり返すようですが——元記事の「省略します」が間違いだったとは、実は思っていません。

ゲーム開発を始めたばかりの段階で大事なのは、とにかく「動いた!」という体験を早く得ることです。細かい条件を全部潰してから先に進もうとすると、たいてい途中で力尽きます。まず動かして、面白さを感じて、それから「あれ、壁でも跳べちゃうな」と気づいて直す。この順番でいいんです。

業務システムは「最初から完璧」を求められる世界。ゲームは「まず動かして、遊びながら育てる」世界。同じプログラミングでも、正しい進め方がまるで違う。 私がUnityで一番面白いと感じたのは、実はこの価値観のギャップでした。

だからこの記事では、あえて両方載せました。「まず動く版(省略あり)」と「気持ち悪さを潰した版(タグ判定)」。あなたの今の気分で、好きなほうを選んでください。

ちなみに、もっと厳密に接地判定をやるなら、OnCollisionEnter だけでは足りない場面(斜面や複数の足場)も出てきます。そこはまた別の記事で。「今回はここまで」——今度は、私が胸を張って省略します。

動きの完成!プレイしてみよう

Cubeオブジェクトを移動させたりジャンプさせている画像

これまでの作業で、CubeはWASDキーでの移動スペースキーでのジャンプができるようになりました。
ここでは、実際にプレイして動作を確認してみましょう。

ゲームを再生して操作を試そう

Unityエディター上部の【▶️再生ボタン】をクリックすると、
ゲームがスタートします。

以下の操作を試してみましょう

操作キー内容
W / A / S / D前後左右に移動
Spaceジャンプ(空中では無効)

スムーズに動けば成功です!

思った通り動かないときのチェックポイント

うまく動かない場合は、次のポイントを確認してみてください:

移動しない場合

  • RigidbodyがCubeにアタッチされているか
  • スクリプト内の moveSpeed が0になっていないか

ジャンプしない場合

  • Input.GetKeyDown(KeyCode.Space)Update() に書かれているか
  • isGroundedfalse のままになっていないか(OnCollisionEnter の書き忘れ)

回転してしまうのが嫌な場合

  • Rigidbody の Freeze Rotation(X/Z) にチェックを入れると安定します

まとめ|業務畑の「違和感」は、Unityでも武器になる

Unity初心者がCube操作を学び終えた達成感を表現したイラスト。シンプルな成功体験のイメージ

お疲れさまでした。これで、Cubeを自由に動かして、ジャンプさせることができました。

でもこの記事で本当にお伝えしたかったのは、動かし方そのものよりも、その途中で私がつまずいた3つのことでした。振り返っておきます。

  • つまずき①:別の時計 — 業務プログラムは「呼ばれてから動く」。でもUnityの Update() は、誰も呼ばないのに毎フレーム勝手に動き続ける。物理は FixedUpdate() という別の時計で動く。この「世界が止まらない」感覚が、ゲーム開発の入口でした。
  • つまずき②:勝手に書き換わるコード — 2022年に書いた rb.velocity が、Unity 6で開いたら rb.linearVelocity に自動で直っていた。フレームワークが黙ってソースを書き換える——業務では恐怖ですが、変化の速いゲーム開発ではありがたい親切でした。
  • つまずき③:省略への違和感 — 「何に触れても再ジャンプOK」なコードに、業務畑の私はゾッとした。でも「まず動かして、遊びながら直す」のもゲーム開発では正解。CompareTag で地面だけに絞って、気持ちよく直しました。

この3つに共通しているのは、業務システムの常識で見たときに「ん?」と引っかかった、という点です。

私は最初、33年の業務経験なんてゲーム開発では役に立たないんじゃないか、むしろ変な癖がついていて邪魔なんじゃないか、と思っていました。でも実際にやってみると、逆でした。「これ、条件が漏れてない?」「これ、環境で動きが変わらない?」という業務で染みついた違和感は、Unityでもちゃんとバグを見つける嗅覚として働くんです。

もしあなたも、業務システムやWindowsアプリを書いてきた人なら。その経験は、遅れてゲーム開発を始めるうえで、足かせではなく武器になります。私はそれを、このCubeを動かすだけの小さなサンプルで確信しました。

次は、この動くCubeに「見た目」を与えていきましょう。次回は〇〇です。それでは、また。

次のステップに進みたくなったら…

もしあなたが「もっと見た目を整えたい」「キャラクターっぽくしたい」と思ったら、
次は アニメーション付きの3Dキャラクターで、同じように移動やジャンプを実装してみましょう!

あるいは、カメラの視点をプレイヤーに追従させたい!と感じたなら、
次は Unity標準のカメラを使って、カメラをキャラクターに追従させる方法をチェックしましょう。

読者様への一言

読者の方へ向けたメッセージのイメージ。

Unityの開発は、ひとつずつ動かして試すことが最短ルートです。

うまくいかなくても大丈夫。
次に「なぜだろう?」と手を止めて考える時間こそが、
あなたの実力をグンと伸ばしてくれます。

📌このブログでは、Unityをこれから学ぶ方へ向けて、
「動く楽しさ」「わかる安心感」を軸に、丁寧な記事を発信しています。

また一歩進みたいときに、ぜひ戻ってきてくださいね!
次のチャレンジも、一緒に取り組んでいきましょう😊

使用しているソフトウェア

  • Unity Editor 6000.3.91f1(LTS)
    ※本文中のエディター画面のスクリーンショットは、Unity Technologies社が提供する開発環境の画像を紹介・解説目的で引用しています。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次