ゲーム開発の壁「C#」を乗り越える|Unityで挫折しないための基礎文法と現場の知恵

目次

「ただ、キャラクターを動かしたかっただけなのに」

私が初めてゲームを作ろうと思ったのは、もう15年以上前のことです。当時はまだUnityなんて便利なものはなく、DirectXという恐ろしく難解なライブラリと格闘していました。黒い画面に白い三角形を一つ表示させるためだけに、3日間もコードを書き続け、エラーと睨めっこした記憶があります。

時代は変わり、今はUnityがあります。画面上にキャラクターをドラッグ&ドロップすれば、とりあえず表示はされる。物理演算をオンにすれば、重力で落下もしてくれる。
「なんだ、ゲーム作りなんて簡単じゃん」
そう思ったのも束の間、多くの初心者が巨大な壁にぶち当たります。

「C#スクリプト」という壁です。

「スペースキーを押したらジャンプさせたい」
ただそれだけのことが、コードを書かないとできない。ネットで検索してコピペしてみたけど、動かない。エラーメッセージは英語で意味不明。数式のような記号の羅列を見て、そっとUnityを閉じてしまう……。

そんな経験、ありませんか?
私がメンターとして担当している受講生の方々も、9割以上がこの「プログラミングの壁」で一度心を折られます。3Dモデルを作ったり、ステージを配置したりするのは楽しい。でも、コードを書く段になると急に手が止まるのです。

しかし、断言します。
ゲーム開発に必要なC#の知識は、実はそんなに多くありません。
分厚い専門書に書かれていることの半分以上は、最初のうちは知らなくてもゲームは作れます。重要なのは「文法を暗記すること」ではなく、「ゲームの中でどう使うか」を理解することです。

現役のエンジニアであり、数多くの「挫折しかけた初心者」を救ってきた私が、ゲーム開発(特にUnity)に必要なC#の基礎を、実戦形式で徹底的に解説します。教科書的な説明は極力省き、「現場でどう使うか」「どこでハマるか」にフォーカスしました。

これを読み終える頃には、あなたの目には、あの無機質なコードの羅列が「キャラクターへの指令書」として鮮明に見えているはずです。さあ、エディタを開く準備はいいですか?

深夜の自室で、PCモニターに映る複雑なC#のコードとUnityの画面を見比べながら、頭を抱えつつも解決の糸口を探している30代男性の線画イラスト

なぜゲーム開発に「C#」なのか?

そもそも、なぜUnityはC#を採用しているのでしょうか。
プログラミング言語にはPythonやJavaScript、C++など様々なものがあります。その中でC#が選ばれている理由を知ることは、学習のモチベーション維持に繋がります。

「読みやすさ」と「速さ」のいいとこ取り

ゲームは処理速度が命です。毎秒60回(60fps)画面を更新するために、膨大な計算を瞬時に行う必要があります。その点ではC++という言語が最強なのですが、これは人間が読み書きするにはあまりにも難解で、メモリ管理などを自分で行う必要があります(ここで多くの先人たちが散っていきました)。

一方で、Pythonなどは書きやすいですが、実行速度が少し遅い。
C#はその中間に位置します。Javaに似た文法で人間にも読みやすく、メモリ管理は自動(ガベージコレクション)でやってくれるのに、実行速度も十分に速い。
Unity TechnologiesがC#をメイン言語に据えたのは、この「開発効率とパフォーマンスのバランス」がゲーム開発に最適だったからです。

膨大な「資産」が使える

UnityでC#を使う最大のメリットは、世界中の開発者が蓄積してきた「知見」と「ライブラリ」が使えることです。
「RPGのインベントリシステムを作りたい」「オンライン対戦を実装したい」
そう思った時、ゼロから作る必要はありません。誰かがC#で書いたコードが、アセットストアやGitHubに転がっています。C#を読めるようになれば、巨人の肩に乗って、自分の作りたいものを最短で実現できるのです。

第1章:変数と型 ~ゲームの世界を「数字」で表現する~

ここから具体的な文法の話に入りますが、教科書のように「intとは整数型です」なんて退屈な説明はしません。ゲーム開発の視点で解説します。

変数は「ステータス画面」そのもの

ゲームを作るとは、突き詰めれば「データを変化させること」です。
HPが減る、経験値が増える、座標が変わる、フラグが立つ。
これらのデータを保存しておく「箱」が変数です。

初心者が最初につまずくのが「型(Type)」の概念です。「なんでいちいち int とか float とか指定しなきゃいけないの? 全部 var じゃダメなの?」と思いますよね。
でも、ゲームにおいて「型」は、そのデータが何者であるかを定義する重要な要素です。

  • int(整数): HP、攻撃力、所持金、アイテムの個数。
    • 1.5個のアイテムなんて存在しませんよね。だから整数です。
  • float(浮動小数点数): 座標、移動速度、タイマー。
    • ゲームの世界では「X座標 10.5」のような細かい位置調整が必要です。Unityで座標や回転を扱うときは、ほぼ100%この float を使います。数字の最後に f をつけるのがお約束です(例: 3.5f)。
  • string(文字列): キャラクターの名前、セリフ、メッセージ。
    • "勇者" のようにダブルクォーテーションで囲みます。
  • bool(真偽値): フラグ。生存しているか(IsAlive)、地面に足がついているか(IsGrounded)。
    • true(真)か false(偽)のどちらかしか入りません。これがゲームの進行管理の要になります。

現場のリアル:publicとprivateの使い分け

UnityでC#を書くとき、変数の前に publicprivate をつけます。これを「アクセス修飾子」と言いますが、初心者はとりあえず全部 public にしがちです。

public int hp = 100;

こう書くと、Unityのエディタ上(Inspectorウィンドウ)で、ゲーム実行中にHPの数値を自由にいじれるようになります。デバッグ調整にめちゃくちゃ便利です。
しかし、現場レベルの話をすると、何でもかんでも public にするのは危険です。他のスクリプトから勝手にHPを書き換えられてしまい、バグの原因になるからです。

プロの現場では、[SerializeField] private という書き方をよく使います。
これは「他のスクリプトからは触らせない(private)けど、Unityのエディタ上からは調整したい(SerializeField)」という、わがままを叶える魔法の呪文です。

[SerializeField] private int hp = 100; // これが現場の推奨スタイル

最初は public でも動きますが、慣れてきたらこの書き方を覚えておくと「お、こいつ出来るな」と思われます。

RPG風のステータス画面をイメージした空間で、変数の箱(HPや攻撃力)を整理したり数値を書き換えたりしているエンジニアの線画イラスト

第2章:条件分岐と繰り返し ~ゲームの「ルール」を作る~

変数があるだけでは、ただのデータの羅列です。そこに「ルール」を与えるのが制御構文です。

if文:すべてのゲームロジックの基本

「もし~なら、こうする」。これがなければゲームは成立しません。

  • もし(HPが0になったら)→ ゲームオーバー画面を出す
  • もし(ボタンが押されたら)→ ジャンプする
  • もし(敵との距離が近かったら)→ 攻撃する
if (hp <= 0)
{
    Die(); // 死ぬ処理
}
else if (hp < 20)
{
    ShowRedScreen(); // 画面を赤くする(ピンチ演出)
}
else
{
    // 何もしない、あるいは通常状態
}

初心者がハマるポイントとして、「比較演算子」があります。
「等しい」は = ではなく == です。= は「代入(右のものを左に入れる)」という意味になってしまいます。
if (hp = 0) と書いてしまい、HPを無理やり0にしてしまうバグは、全人類が一度は通る道です。

for文とforeach文:敵を100体出す魔法

「敵を1体出現させる」コードは書けた。でも、100体出したい時はどうするか?
同じコードを100行コピペしますか? しませんよね。そこでループ処理の出番です。

// 100回繰り返す
for (int i = 0; i < 100; i++)
{
    SpawnEnemy(); // 敵を出す処理
}

Unity開発では、配列やリストと一緒に使う foreach も頻出です。
例えば、「画面内にいる全ての敵にダメージを与える」といった処理です。

// enemiesというリストに入っている全ての敵に対して処理をする
foreach (var enemy in enemies)
{
    enemy.TakeDamage(10);
}

これを使いこなせると、「弾幕シューティング」や「大量のゾンビが襲ってくるゲーム」が作れるようになります。コンピュータの得意技である「単純作業の高速繰り返し」を武器にするのです。

第3章:メソッド(関数) ~処理をまとめる「魔法の呪文」~

コードが長くなってくると、どこで何をしているのか分からなくなります。スパゲッティコードの誕生です。
これを防ぐために、一連の処理をひとまとめにして名前をつけるのがメソッド(関数)です。

攻撃処理をパッケージ化する

例えば、攻撃ボタンを押した時の処理が「アニメーション再生」「音を鳴らす」「当たり判定を出す」「スタミナを減らす」の4つだったとします。これを毎回書くのは大変です。

void Attack()
{
    PlayAnimation("Attack");
    PlaySound("SwordSlash");
    EnableHitBox();
    stamina -= 10;
}

こうやって Attack というメソッドを作っておけば、あとは必要な場所で Attack(); と唱えるだけで、これら全ての処理が実行されます。
メソッドを作ることは、「自分だけの命令文を作る」ことと同じです。

引数と戻り値:情報のキャッチボール

メソッドはただ命令するだけでなく、情報を渡したり、結果を受け取ったりできます。

  • 引数(ひきすう): メソッドに渡す材料。
    • Attack(50); なら「攻撃力50で攻撃しろ」という意味になります。
  • 戻り値(もどりち): メソッドから返ってくる結果。
    • bool isHit = CheckHit(); なら「攻撃が当たったかどうか(true/false)」を受け取ります。

初心者のうちは void(戻り値なし)ばかり使いがちですが、計算結果を返すメソッドを作れるようになると、コードの再利用性がグンと上がります。
例えば「レベルに応じた必要経験値を計算するメソッド」を作っておけば、UI表示でもレベルアップ判定でも使い回せますよね。

魔法使いのような姿をしたエンジニアが、「メソッド」という呪文を唱えて、複雑な処理を一瞬で実行させている様子の線画イラスト

第4章:クラスとオブジェクト指向 ~量産と管理の技術~

ここが最大の難所です。多くのチャレンジャーがここで脱落します。
「クラスって何? インスタンスって何?」
専門用語を使わずに説明しましょう。

クラスは「設計図」、インスタンスは「実体」

たい焼きで例えるのが有名ですが、ゲーム開発なら「モンスターのデータ」で考えると分かりやすいです。
「スライム」というモンスターを作りたいとします。スライムにはHPがあり、攻撃力があり、体当たりしてきます。

この「スライムの仕様書」にあたるのがクラスです。

public class Slime
{
    int hp = 10;
    int attack = 3;

    void JumpAttack()
    {
        // 飛び跳ねて攻撃する処理
    }
}

しかし、このコードを書いただけでは、ゲーム画面には何も現れません。あくまで「仕様書(設計図)」を書いただけだからです。
この設計図を元に、メモリ上に生み出された「実際のスライムA」「スライムB」のことをインスタンス(実体)と呼びます。

Unityの場合、この概念が少し特殊で視覚的です。
C#スクリプト(Slime.cs)を書くことが「クラスを作る」ことにあたり、それをGameObjectにアタッチしたり、プレハブとしてシーンに配置したりしたものが「インスタンス」になります。
「スクリプトを書いたのに動かない!」という初心者の悩みは、大抵「設計図を書いただけで、実体をシーンに置いていない(アタッチしていない)」ことが原因です。

コンポーネント指向:Unityならではの流儀

一般的なC#のオブジェクト指向と、Unityの流儀には少し違いがあります。
Unityは「コンポーネント指向」という考え方を採用しています。
これは、「空っぽのGameObject」に、「機能(コンポーネント)」をペタペタ貼り付けていくことでキャラクターを作る方法です。

  • 「位置情報」が必要なら Transform コンポーネント
  • 「絵」が必要なら SpriteRenderer コンポーネント
  • 「物理挙動」が必要なら Rigidbody コンポーネント
  • 「独自の動き」が必要なら、あなたが書いた C#スクリプト

あなたが書くC#スクリプトも、あくまで「一つの部品(コンポーネント)」として扱われます。
だからこそ、Unityのスクリプトは必ず MonoBehaviour というクラスを継承(継ぎ足し)して作られるのです。
MonoBehaviour って何?」と深く考える必要はありません。「Unityの部品として動くための基本機能セット」だと思ってください。これがないと、GameObjectに貼り付けることができません。

工場のラインのような場所で、クラスという「設計図」から次々とロボット(インスタンス)が製造され、それぞれが動き出す様子の線画イラスト

第5章:Unity特有の「お約束」メソッド

Unityでゲームを作る際、避けて通れない特別なメソッドたちがいます。これらは自分で呼ぶのではなく、Unity側が「特定のタイミング」で勝手に呼んでくれるものです。これをイベント関数と呼びます。

Start() と Update()

スクリプトを作ると最初から書かれているこの二人。

  • Start(): ゲームが始まった瞬間(またはそのオブジェクトが生まれた瞬間)に、1回だけ呼ばれます。
    • HPの初期化、アイテムの装備、コンポーネントの取得など、「準備運動」に使います。
  • Update(): ゲーム中、1フレームごとに毎回呼ばれ続けます。
    • キー入力の検知、移動処理、タイマーのカウントなど、「動き続けるもの」はここに書きます。

初心者がよくやるミスが、「1回だけでいい処理(例:BGMの再生開始)」を Update() に書いてしまうこと。すると、1秒間に60回も「再生しろ!再生しろ!」と命令され、音がバグったり処理落ちしたりします。
「これはずっと監視すべきことか? 最初だけでいいことか?」を常に意識してください。

GetComponent():隣の部品を借りる

スクリプトから、同じオブジェクトについている別のコンポーネント(例:物理演算をするRigidbody)を操りたい時、どうすればいいでしょうか。
そこで使うのが GetComponent<型名>() です。

Rigidbody2D rb;

void Start()
{
    // 同じオブジェクトについているRigidbody2Dを探してきて、変数rbに入れる
    rb = GetComponent<Rigidbody2D>();
}

void Update()
{
    // rbを使って上に力を加える(ジャンプ)
    rb.AddForce(Vector2.up * 10);
}

これも初心者のバグの温床です。GetComponent は意外と重い処理なので、Update() の中で毎回呼んではいけません。Start() で一度だけ呼んで変数にキャッシュ(保存)しておく。これが現場の鉄則です。

第6章:実践!バグとエラーとの付き合い方

コードを書けば、必ずエラーが出ます。ベテランでも出ます。
エラーが出た時、初心者は「才能がない」と落ち込みますが、プロは「ヒントが出た」と喜びます(嘘です、舌打ちはします)。

赤い波線は「文法ミス」

エディタ上で出る赤い波線は、コンパイルエラー。つまり「C#の言葉として間違っているよ」という指摘です。

  • ;(セミコロン)の付け忘れ
  • { }(波括弧)の閉じ忘れ
  • スペルミス(Startstart と書くなど)

これらは実行前に直せます。Visual StudioなどのIDE(統合開発環境)が教えてくれるヒントをよく読みましょう。

Consoleの赤い文字は「実行時エラー」

UnityのConsoleウィンドウに出る赤いエラー。これは「文法は合ってるけど、実行中に矛盾が起きたよ」という合図です。
代表的なのが NullReferenceException。通称「ぬるぽ」。
「空っぽ(Null)の箱の中身を使おうとしましたよ」というエラーです。

  • GetComponent で取得しようとしたコンポーネントがついていなかった。
  • Inspectorで設定すべき変数が、空欄のままだった。

このエラーが出たら、まずは「どの変数が空っぽなのか」を疑ってください。Debug.Log(変数名); を仕込んで、中身を確認するのが調査の第一歩です。

ログ出力こそ最強のデバッグ

Debug.Log("ここを通った");
これをコードのあちこちに仕込むこと。これが最強のデバッグ術です。
if文の中にこれを入れて、ログが出なければ、そもそも条件分岐に入れていないことが分かります。
プログラミングは推測でやってはいけません。ログという証拠を見て、事実に基づいて修正するのです。

PC画面に表示された赤いエラーログを見て一瞬焦るが、深呼吸してログの内容を読み解き、解決策を見つけてニヤリとするエンジニアの線画イラスト

第7章:学習を続けるためのマインドセット

C#の基礎を一通り覚えたとしても、ゲーム作りにはまだまだ壁があります。
「作りたい機能の実装方法がわからない」
「エラーがどうしても消えない」

そんな時、どうすればいいのでしょうか。

「リファレンス」を恐れない

Unity公式のスクリプトリファレンスは、最初は呪文のように見えるかもしれません。でも、あそこには全ての正解が書いてあります。
ネットの技術記事(QiitaやZenn)は分かりやすいですが、情報が古かったり間違っていたりすることもあります。
最終的に信頼できるのは公式ドキュメントです。「Unity Rigidbody」などで検索し、公式の説明を読む癖をつけましょう。最初は意味がわからなくても、用語に慣れるだけで成長します。

100点を目指さない

初心者が挫折する最大の理由は「理想が高すぎること」です。
最初から市販のRPGのようなものを作ろうとしてはいけません。
まずは「四角い箱が動くだけ」でいいんです。「クリックしたら音が鳴るだけ」でいいんです。
小さな成功体験を積み重ねてください。クソゲー上等です。動けば勝ちです。

FAQ:よくある質問

Q. 数学が苦手ですが、ゲームプログラミングはできますか?
A. できます。高校レベルの三角関数(サイン・コサイン)やベクトルが分かると便利ですが、Unityにはそれを肩代わりしてくれる便利な関数がたくさんあります。例えば「敵の方を向く」処理も、数学を使わずに Transform.LookAt() 一発で済みます。必要になった時に調べれば十分です。

Q. 独学とスクール、どっちがいいですか?
A. 独学でも可能ですが、エラーで詰まった時の「時間のロス」が膨大です。何日も悩んだエラーが、メンターに見せたら3秒で解決した、なんてことは日常茶飯事です。時間を金で買うつもりならスクール、時間をかけてでも自力で解決する力をつけたいなら独学、という選び方が良いでしょう。

Q. C#以外の言語(JavaScriptなど)じゃダメですか?
A. 昔のUnityはJavaScript(UnityScript)も使えましたが、今は廃止されました。UnityをやるならC#一択です。他の言語に逃げ道はありませんが、逆に言えばC#さえ覚えればOKということです。

おわりに:あなたのコードが世界を作る

ここまで、ゲーム開発におけるC#の基礎について解説してきました。
変数、if文、メソッド、クラス…。最初は無機質な記号に見えたものが、少しは意味のある言葉に見えてきたでしょうか。

プログラミングは、コンピュータへの手紙です。
「右へ動いて」「ぶつかったら消えて」「スコアを増やして」
あなたのその想いを、C#という言葉で伝えるだけです。

私も最初は、if文の書き方すら分かりませんでした。
それでも、拙いコードを書き継いで、初めて自分のキャラクターが画面の中でジャンプした時。あの瞬間の感動は、何物にも代えがたいものでした。
まるで、自分の中に神様が宿ったような、世界を創造したような感覚。

あなたにも、その感覚を味わってほしい。
エラーが出ても諦めないでください。それは、あなたのゲームが完成に近づいている証拠です。
今日覚えた知識を武器に、まずは1行、コードを書いてみてください。

その1行が、あなたの想像する壮大な世界の、最初のレンガになります。
さあ、Unityを開きましょう。あなたの冒険は、ここから始まります。

完成したゲームがモニターの中で動いており、それを友人にプレイさせながら、誇らしげな笑顔で見守っているエンジニアの線画イラスト

あなたの書いたコードが、誰かの心を動かす日が来ることを、心から信じています。
まずは Debug.Log("Hello World!"); から始めてみましょう。
健闘を祈ります!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いたエンジニア

小林 朋子のアバター 小林 朋子 アプリケーションエンジニア

アプリケーション開発に精通したエンジニアで、丁寧な設計と柔軟な対応力が強み。親しみやすい性格で、周囲を自然と明るくするタイプ。休日は映画鑑賞やカフェでのんびりするのが好き。バランス感覚に優れた安定感のある人物。

目次