はじめに
今朝、事始にUnityで空プロジェクトを作成して、シンプルなアプリを制作しました。
それにあたって、開発環境の基本操作が何も分からないので、情報をまとめてみました。
こういうのは覚えるより、使いながら学ぶ方が身につくと思いますが、一応、後から再学習できるようにざっと目を通せる形でまとめてみます。
[Unity] #01:CubeとPlaneで始める最短入門(Three.js経験者向け)
Unity 6 (URP) を使い、CubeとPlaneの生成、Rigidbodyによる物理、WASD移動、カメラ操作、Mesh変形までを最短ルートで確認する記録。Three.js経験者視点で、Unity特有の罠とGUIの壁を整理する。
https://humanxai.info/posts/unity-01-cube-plane-wasd-camera/1. ゲームオブジェクトへスクリプトをつける流れ
Unity で最初に理解すべきポイントは、「コード(Script)がコンポーネントとして GameObject にアタッチされて動く」という発想そのものだ。Three.js では mesh.position.x += ... のように“オブジェクトを直接いじるコードがそのまま動く”が、Unity はまったく違う仕組みで動く。
Unity の基本思想:GameObject + Component
Unity の世界は、すべてのオブジェクトを GameObject として扱い、 そこに動作や性質を Component として積み上げる構造になっている。
- Transform
- MeshRenderer
- BoxCollider
- Rigidbody
- Script(C#)
これら全部「Component」。 コードも “Component の一種” と捉えると理解が速くなる。
スクリプトを動かすまでの標準フロー
Unity で自分のコードを動かすには、次の流れが必須になる。
-
Assets フォルダで C# Script を作成する
-
対象の GameObject を選択する
-
Inspector に Script をアタッチする
- ドラッグ&ドロップ
- または “Add Component” → Script を選択
-
初めてコードが実行可能になる
Three.js のように「import したら勝手に動く」世界ではない。 “アタッチして初めてその GameObject の一部として認識される”。
ここを理解するだけで、Unity でのコードの流れが一気にスッキリする。
よくある初手のつまずき:「スクリプトが動かない」
Unity 初心者が必ず踏む地雷がこれ。
スクリプトが動かない → 原因は 99% “アタッチ漏れ” または Assets 外にファイルを置いた ことによるエラー。
- Script を
Assets外に置いている - Script のクラス名とファイル名が一致していない
- GameObject にアタッチしていない
- Add Component で検索しても出てこない(置き場所が原因)
こういう「動かない理由」が Unity 特有で、Three.js と比べて圧倒的に多い。
Three.js との思考差分
Three.js:
- オブジェクト生成
- 変数に保持
- 直接いじると即結果に反映
Unity:
- GameObject
- そこに必要な要素(Renderer / Collider / Script)を Component として積む
- Script は GameObject に載せないと動作しない
この“Component 方式”の理解が腹落ちすると、Editor の構造もスムーズに理解できる。
2. Update と FixedUpdate の違い
Unity を触り始めてすぐ直面するのが、Update と FixedUpdate の役割の違いだ。 Three.js には存在しない概念なので、ここを理解していないと「なんで動きがカクつく?」という理由がつかめない。
Update:フレームごとに呼ばれる(入力・カメラ向き)
Update() は 毎フレーム 呼ばれる処理。
描画のタイミングに合わせて実行されるため、フレームレートが変動すると呼ばれる回数も変わる。
適している処理:
- WASD の入力を取る
- マウス入力
- カメラの向きや回転
- UI の更新
つまり、Three.js の requestAnimationFrame() 内でやっていた処理に近い。
可変フレームで問題ない “入力系・見た目系” をここに書く。
FixedUpdate:一定間隔で呼ばれる(物理)
一方で、FixedUpdate() は 一定間隔(デフォルト 0.02s)で必ず呼ばれる。
ここが物理演算(Rigidbody)と紐づいており、処理のタイミングが固定されている。
適している処理:
- Rigidbody を使った移動
- 重力
- Jump
- 力・速度の更新
- 衝突計算
Three.js では Ammo.js や Cannon.js を使ったときに“物理演算は別で回す”のに近い。 Unity はそれが標準で組み込まれていて、物理用ループ(FixedUpdate)が自動で回っている。
Update に書いたせいで挙動が不安定になる例
初心者がよくやるパターン:
rb.AddForce(...); // Update に書いてしまう
結果:
- フレームレートが低いと動きが鈍い
- フレームレートが高いと飛び跳ねる
- 重力が安定せず挙動がおかしい
これは、Force の加算がフレーム依存になってしまうのが原因。
物理に触れるコードは必ず FixedUpdate() 側に寄せる必要がある。
移動(WASD)は Update、物理は FixedUpdate
学んだ通り、WASD の入力は Update に置くのが正解。 実際の Rigidbody の移動は FixedUpdate に任せる。
Unity は “入力” と “物理” を別サイクルで処理する設計になっている。 これが理解できると、キャラの移動もジャンプも安定して動く。
Three.js と比較したイメージ
Three.js:
animate()内で全部処理- 物理が必要なら外部ライブラリのステップを自前で呼ぶ
Unity:
- 入力 → Update
- 物理 → FixedUpdate
- それぞれが別のペースで回っている(自動管理)
この分離が Unity の挙動の安定につながっている。
3. 物理(Rigidbody と Collider)を理解した瞬間
Unity の物理で一番大事なのは、「見た目」と「物理」は完全に別物だと割り切ることだ。 Three.js では Mesh がそのまま当たり判定っぽく振る舞う感覚があるけれど、Unity では何も設定しない限り、ただの見た目でしかない。
Rigidbody がないと重力は発生しない
Unity で「重力が効かない」と感じたら、まず疑うべきはこれ。
- Transform だけ → 何も起きない
- Rigidbody を追加 → 初めて重力の対象になる
重力は自動ではかからない。 Rigidbody が付いた GameObject だけが、物理世界に参加できる。
ここを理解した瞬間に、「あ、物理は opt-in なんだ」と腑に落ちる。
Collider がないと“当たっていない”扱い
次にハマるのがこれ。
- Rigidbody はある
- でも Collider がない
- 結果:床をすり抜ける
Unity では、衝突判定は Collider が担当している。 見た目の Mesh は衝突判定に一切関与しない。
- BoxCollider
- SphereCollider
- CapsuleCollider
- MeshCollider
このどれかが付いて、初めて「そこに物がある」扱いになる。
プレーンとキューブで役割が違う理由
サンプルで、
- Plane:BoxCollider のみ
- Cube:Rigidbody + Collider
という構成にした意味が、ここで一気につながる。
- 床は動かない
- キャラ(キューブ)は落ちる・ぶつかる・動く
床に Rigidbody は不要。 “動かないものは Collider だけでいい” という設計になる。
逆に、キューブは物理演算の対象にしたいので Rigidbody が必須。
Three.js との感覚の違い
Three.js では、
- Mesh = 見た目
- 当たり判定は自前 or ライブラリ依存
Unity では、
- MeshRenderer = 見た目
- Collider = 形
- Rigidbody = 物理挙動
役割が完全に分離されている。
この分離を理解すると、
- なぜすり抜けるのか
- なぜ落ちないのか
- なぜ勝手に動くのか
全部、設定の不足や過剰として説明できるようになる。
物理を理解すると Editor が味方になる
Inspector を見て、
- Rigidbody が付いているか
- Collider のサイズが合っているか
- Is Trigger になっていないか
ここを確認するだけで、多くのトラブルは解決する。
この段階まで来ると、Unity は「よくわからない黒魔術」じゃなく、部品を組み合わせるエンジンとして扱えるようになる。
4. カメラ制御との関係
Unity のカメラは、Three.js のように OrbitControls が最初から付いている前提ではない。 ここを理解していないと、「カメラをどう動かすのが正解?」という疑問で止まる。
Unity では、カメラの挙動は自分で組むのが基本姿勢だ。
Camera をプレイヤーの「子」にする方法
もっともシンプルなのが、Camera をプレイヤー(キューブなど)の子オブジェクトにする方法。
Player
└── Camera
こうすると、
- Player を WASD で動かす
- Camera は Transform を継承して自動追従
という、最も簡単で扱いやすい挙動が手に入る。
視点の相対位置は Transform の Inspector で固定できるので、コードを書く量も最小になる。
“とにかく動くカメラ” が欲しいなら、この構成が最速。
スクリプトで Camera を追従させる方法
一方で、もう少し自由度の高いカメラにしたい場合はスクリプトで追従させる。
例:
- プレイヤーの少し後ろに追従
- プレイヤーの向きに合わせてカメラも回転
- 追従速度に補間を入れる(滑らかにする)
Unity ではこのあたりを Update や LateUpdate で書く。
Three.js で OrbitControls の設定をいじっていた感覚とは違って、 Camera の挙動そのものを自分で設計する世界になる。
慣れれば「必要な動きだけ書ける」ので自由度が高い。
OrbitControls 相当は自分で作る世界観
Three.js:
- OrbitControls が標準
- ぐるっと回せばもうそれっぽいカメラ
Unity:
- デフォルトで何も付かない
- 回転・ズーム・追従は全部スクリプト or Cinemachine
Unity の思想としては、
“カメラはゲームごとに全く違うので、自前で挙動を組んでね”
というスタンス。 そのぶん Three.js 以上にカメラの自由度が高い。
Cinemachine という強力な選択肢もある
Unity には OrbitControls 的な便利ツールとして Cinemachine が標準で用意されている。
- 被写体追跡
- 視点切り替え
- スムーズなカメラワーク
- 遅れ追従(ダンピング)
こういった高度なカメラ挙動がノーコードで作れる。
ただし、まずは Camera を子にする or スクリプト追従の基礎を理解してからのほうが扱いやすい。
“Unity のカメラは自前で作る” を理解した瞬間に楽になる
Three.js で OrbitControls に慣れていると、最初は不便に感じるかもしれない。 だけど Unity の利点は、ゲームのコンセプトに完全最適化されたカメラを組めること。
- TPS
- FPS
- 俯瞰ゲーム
- 横スクロール
- 固定カメラ
- 自動追従カメラ
全部、自分が必要な分だけ実装すればいい。
Unity を触り始めたばかりでも、Camera を親にするだけで一気に理解が進むので、ここは必ず押さえておくポイントになる。
5. Editor 操作と PlayMode の落とし穴
Unity を触り始めて一番ストレスが溜まるのは、「操作したつもりが反映されてない」問題だ。 Three.js のように全部コード管理ではないぶん、Editor の仕様を理解していないと絶対に混乱する。
ここは初心者が確実に踏む地雷だけをまとめる。
PlayMode 中の変更は消える
Unity の大前提として、
Play(再生)中に Inspector で変更した値は、基本的に Play を止めると消える。
- Position を微調整
- パラメータをいじっていい感じになった
- 再生停止
- すべて元に戻る
これで「え?」となる人は多い。 対策は簡単で、本番の値は PlayMode の外でいじる。 (実際には “Enter Play Mode Options” など例外はあるが、最初は気にしないで正解)
MoveTool 中に違うオブジェクトを触るとズレる
Unity では、Scene ビューでドラッグ操作したあとは Inspector のフォーカスが残ったままになる。
例えば:
- Cube を選択
- MoveTool で床をつまんで動かそうとする
- 実は Cube の Transform が動いていた
こういう地味なのに強烈な事故が起きる。
Three.js のようにコードで位置を管理する世界では起きないタイプのミスなので、Unity では「今どのオブジェクトが選択されてるか」を常に確認する癖が役立つ。
Apply しないと Prefab に反映されない
Prefab を編集していても、Apply しない限り元の Prefab には反映されない。
- 子オブジェクトを追加
- 色を変える
- Collider のサイズを調整
- なんか直した → Apply を押し忘れると全てローカルだけの変更扱い
Prefab は “設計図” なので、Apply を押して初めて設計図に上書きされる。
初心者はここを忘れて「修正が反映されない」と騒ぎがち。
Scene の保存忘れ
Unity は “Scene” という単位で編集を保持する。
- Ctrl+S / Cmd+S を押し忘れる
- Unity を閉じる
- 大量にやった変更がなかったことになる
特に初心者は Scene と Project の保存が別だと気付きにくい。
- Script の保存 → Visual Studio / Rider 側
- Scene の保存 → Unity 側
このズレが理解できていないと、突然のロスが起きる。
この4つを覚えたら Editor のストレスが激減する
Unity Editor は便利だけど、仕様を知らないとミスが UI の裏で静かに積み上がる。 基本的な落とし穴はこの通り:
- PlayMode 中の変更は消える
- 間違ったオブジェクトを掴む事故
- Prefab は Apply しないと反映されない
- Scene の保存忘れで変更が消える
このあたりを理解しておけば、三大ミス「反映されない・元に戻る・消える」の大半は避けられる。
6. Three.js → Unity の人が陥る思考差分
Three.js に慣れている人ほど、Unity の最初の壁は 「思想の違い」 そのものになる。 同じ 3D 表現を扱っているのに、設計思想がまったく別物だからだ。
ここを理解しておくと、Unity の操作が急にスムーズになる。
“コード主体”から“シーン主体”に切り替わる
Three.js の基本は、コードがすべてを支配するスタイル。
new THREE.Mesh(...)mesh.position.set(...)scene.add(mesh)renderer.render(scene, camera)
この流れの中で全部が完結する。
Unity は逆で、Scene にオブジェクトを並べて、それにコードを添えるスタイル。
- シーンに Cube を置く
- コンポーネントを積む
- 必要なら Script を付ける
「まず Scene を作る → コードは補助」 ここが根本的に違う。
何でも script で書こうとすると逆に面倒になる
Three.js の癖のまま Unity を触ると、
- Camera をコードで作ろうとする
- Light をコードで作ろうとする
- オブジェクト生成もコードで管理したがる
こうなって、Unity の利点(Editor)を丸ごと捨てることになる。
Unity は “Scene に置くもの”と“Script で制御するもの”が明確に分かれているので、 Three.js のノリで全部コード管理すると苦労しか残らない。
“Inspector に値を持たせる”文化
Three.js は基本的に 全部コード側の変数で完結する。
Unity は反対で、
- speed
- rotationSpeed
- jumpPower
- cameraOffset
- gravityScale
こういったパラメータは Inspector に公開して設定するのが主流。
public float speed = 5f;
こうすることで、
- 値をいちいちコードで書き換えなくていい
- テストしながら最適値を探せる
- デザイナーとの共同作業がしやすい
という Unity の強みを最大限活かせる。
「値はコードに書くより Inspector に持たせる」という思想に切り替えると、Unity での開発効率が一気に上がる。
Prefab(青い箱)は Three.js に存在しない概念
Three.js で近いものは「クラス化」だが、Unity の Prefab はもっと強力。
Prefab とは:
GameObject の構成(子オブジェクト・コンポーネント・パラメータ)を丸ごと保存した“設計図”
メリット:
- コピーしても一元管理できる
- 修正を一気に反映できる(Apply)
- インスタンスとテンプレートが自動で紐づく
- シーンに大量配置しても設定が崩れにくい
Three.js の mesh 複製のような単純コピーとは別次元の機能。
Unity の大規模制作では Prefab が中心になるので、ここを理解すると Editor も見え方が変わる。
この思考差分が腑に落ちると、Three.js から Unity への移行が一気に楽になる。 「Unity のやり方」に合わせた瞬間、Editor と Script の役割分担がハッキリして、開発スピードも上がる。
💬 コメント