CSharp for Unity入門|初心者がゲーム開発でつまずくC#基礎と実践手順

はじめに

Unityでゲーム開発を始めた初心者が最初につまずきやすいのが、C#スクリプトです。画面上でオブジェクトを配置するだけなら直感的に操作できますが、キャラクターを動かす、アイテムを取る、スコアを増やす、ゲームオーバーを判定するといった処理にはプログラムが必要になります。

「csharp for unity」や「CSharp for Unity」と検索する人の多くは、一般的なC#の文法を知りたいだけではなく、「Unityの中でC#をどう使えばゲームが作れるのか」を知りたいはずです。

この記事では、Unity初心者が押さえておきたいC#の基礎文法から、実際にキャラクターを動かす手順、当たり判定、スコア表示、よくあるエラーの解決方法までを、ゲーム開発目線で解説します。

1. CSharp for Unityとは?初心者が最初に知るべき全体像

1-1. Unityで使うC#とは何か

Unityで使うC#は、ゲーム内の動きやルールを作るためのプログラミング言語です。

たとえば、次のような処理はC#で書きます。

  • プレイヤーをキーボードで動かす

  • 敵を自動で移動させる

  • アイテムを取ったらスコアを増やす

  • HPが0になったらゲームオーバーにする

  • ボタンを押したらシーンを切り替える

Unityでは、C#で書いたファイルを「スクリプト」と呼びます。このスクリプトをGameObjectにアタッチすることで、画面上のキャラクターやアイテムに動きや機能を追加できます。

つまり、UnityにおけるC#は「ゲームオブジェクトに命令を与えるための言語」と考えると理解しやすいです。

1-2. 通常のC#とUnity向けC#の違い

C#自体は、Unity専用の言語ではありません。Webアプリ、デスクトップアプリ、業務システムなど、さまざまな分野で使われています。

ただし、Unityで使うC#にはUnity独自の書き方があります。

たとえば、通常のC#ではプログラムの開始地点としてMainメソッドを使うことがありますが、Unityでは基本的にStart()Update()を使います。

C#
void Start()
{
Debug.Log("ゲーム開始時に一度だけ実行");
}

void Update()
{
Debug.Log("毎フレーム実行");
}

また、UnityではGameObjectTransformRigidbodyColliderMonoBehaviourなど、Unity専用のクラスや機能を多く使います。

そのため、C#の文法だけを学んでも、すぐにUnityでゲームを作れるとは限りません。大切なのは、C#の基礎とUnity独自の仕組みをセットで理解することです。

1-3. 「CSharp for Unity」で検索する人が知りたいこと

「CSharp for Unity」と検索する人が知りたいのは、主に次のような内容です。

  • UnityでC#をどう書けばいいのか

  • 初心者はどの文法から覚えるべきか

  • スクリプトをGameObjectにどう使うのか

  • キャラクター移動やジャンプをどう実装するのか

  • エラーが出たときにどう直せばいいのか

  • C#未経験でもUnity開発を始められるのか

Unity学習で重要なのは、最初からC#を完璧に理解しようとしないことです。ゲームを作りながら、必要な文法を少しずつ覚えていく方が効率的です。

1-4. プログラミング未経験でもUnityのC#は学べるのか

プログラミング未経験でも、UnityのC#は学べます。

ただし、最初から大きなRPGやオンラインゲームを作ろうとすると、ほぼ確実につまずきます。まずは、次のような小さな機能を作るところから始めるのがおすすめです。

  • キャラクターを左右に動かす

  • スペースキーでジャンプする

  • コインを取ると消える

  • スコアが1増える

  • 穴に落ちたらゲームオーバーになる

このような小さな処理を積み重ねることで、C#の文法とUnityの考え方が自然に身につきます。

2. UnityでC#を始める前に必要な準備

2-1. Unity HubとUnity Editorのインストール

UnityでC#を使うには、まずUnity HubとUnity Editorをインストールします。

Unity Hubは、Unity Editorのバージョン管理やプロジェクト作成を行うための管理ツールです。Unity Editorは、実際にゲーム画面を作ったり、スクリプトをアタッチしたりする開発環境です。

初心者は、特別な理由がなければLTS版を選ぶと安心です。LTS版は長期サポート版のため、学習中に大きな仕様変更で混乱しにくいというメリットがあります。

インストール時には、必要に応じて以下のモジュールも追加します。

  • Windows向けにビルドするならWindows Build Support

  • macOS向けにビルドするならMac Build Support

  • Androidアプリを作るならAndroid Build Support

  • iPhone向けに作るならiOS Build Support

最初はPC上で動くゲームを作れれば十分なので、必要最低限の構成から始めても問題ありません。

2-2. Visual Studio・VS Codeなどコードエディタの設定

UnityのC#スクリプトを書くには、コードエディタを使います。代表的なのはVisual StudioとVisual Studio Codeです。

初心者にはVisual Studioが扱いやすいです。Unityとの連携がしやすく、入力補完やエラー表示も使いやすいためです。

Unity側では、外部スクリプトエディタを設定しておきます。

Unity Editorのメニューから、Preferencesまたは環境設定を開き、External Toolsの項目で使用するエディタを選択します。

エディタ連携が正しくできていると、UnityでC#スクリプトをダブルクリックしたときに、指定したエディタでコードが開きます。

2-3. 新規プロジェクト作成とスクリプト追加の流れ

UnityでC#を使う基本的な流れは次のとおりです。

  1. Unity Hubで新規プロジェクトを作成する

  2. 2Dまたは3Dテンプレートを選ぶ

  3. ProjectウィンドウでC# Scriptを作成する

  4. スクリプト名を決める

  5. スクリプトをダブルクリックして編集する

  6. GameObjectにスクリプトをアタッチする

  7. Playボタンで実行する

たとえば、PlayerControllerというスクリプトを作成した場合、ファイル内のクラス名も同じPlayerControllerにする必要があります。

C#
using UnityEngine;

public class PlayerController : MonoBehaviour
{
void Start()
{
Debug.Log("PlayerControllerが動きました");
}
}

ファイル名とクラス名が一致していないと、Unity側で正しく認識されないことがあります。初心者がよくつまずくポイントなので注意しましょう。

2-4. C#スクリプトがUnity上で動く仕組み

Unityでは、C#スクリプトを作成しただけではゲーム内で動きません。スクリプトをGameObjectにアタッチする必要があります。

たとえば、プレイヤーを動かすスクリプトなら、プレイヤーのGameObjectにアタッチします。カメラを追従させるスクリプトなら、カメラのGameObjectにアタッチします。

Unityはゲーム実行中に、GameObjectに付いているスクリプトを確認し、Start()Update()などのメソッドを自動で呼び出します。

この「Unityが特定のタイミングでメソッドを呼んでくれる」という仕組みを理解すると、C#スクリプトの動きが分かりやすくなります。

3. 初心者がつまずきやすいC#基礎文法

3-1. 変数と型:int・float・string・boolの使い分け

変数とは、数値や文字などのデータを入れておく箱のようなものです。C#では、変数を作るときに型を指定します。

Unity初心者が最初に覚えるべき型は、次の4つです。

C#
int score = 0;
float speed = 5.0f;
string playerName = "Hero";
bool isGameOver = false;

intは整数、floatは小数、stringは文字列、boolは真偽値を表します。

ゲーム開発では、次のように使い分けます。

C#
int hp = 100;              // HPやスコア
float moveSpeed = 3.5f; // 移動速度
string itemName = "Coin"; // アイテム名
bool isGrounded = true; // 地面にいるかどうか

Unityでは位置や速度に小数を使うことが多いため、floatは特によく使います。数値の後ろにfを付けるのを忘れないようにしましょう。

3-2. if文でゲームの条件分岐を作る

if文は、「もし条件を満たしたら処理を実行する」という文法です。

C#
if (hp <= 0)
{
Debug.Log("ゲームオーバー");
}

ゲームでは、条件分岐を頻繁に使います。

C#
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("ジャンプ");
}

このコードは、スペースキーが押された瞬間に「ジャンプ」と表示します。

elseを使うと、条件を満たさなかった場合の処理も書けます。

C#
if (isGameOver)
{
Debug.Log("操作できません");
}
else
{
Debug.Log("操作できます");
}

Unityのゲームロジックは、ほとんどが条件分岐の組み合わせで作られています。

3-3. for文・while文で繰り返し処理を書く

繰り返し処理には、for文やwhile文を使います。

for文は、決まった回数だけ処理を繰り返したいときに便利です。

C#
for (int i = 0; i < 5; i++)
{
Debug.Log(i);
}

このコードは、0から4までの数字を表示します。

一方、while文は、条件を満たしている間だけ繰り返します。

C#
int count = 0;

while (count < 3)
{
Debug.Log(count);
count++;
}

ただし、Unity初心者はwhile文の無限ループに注意が必要です。条件がずっとtrueのままだとUnityが固まることがあります。

ゲーム開発では、複数の敵やアイテムを生成するときに繰り返し処理を使うことが多いです。

3-4. メソッドで処理を分けて読みやすくする

メソッドとは、処理をひとまとまりにしたものです。

たとえば、ジャンプ処理をUpdate()の中に直接書くと、コードが長くなって読みにくくなります。そこで、処理をメソッドに分けます。

C#
void Update()
{
Move();
Jump();
}

void Move()
{
Debug.Log("移動処理");
}

void Jump()
{
Debug.Log("ジャンプ処理");
}

このようにすると、Update()の中身を見ただけで「移動」と「ジャンプ」をしていることが分かります。

Unity開発では、最初から完璧に整理する必要はありません。ただ、処理が長くなってきたらメソッドに分ける習慣をつけると、後から修正しやすくなります。

3-5. クラスとオブジェクトの考え方をUnity目線で理解する

C#では、クラスは設計図のようなものです。オブジェクトは、その設計図から作られた実体です。

Unityでは、C#スクリプトのクラスをGameObjectにアタッチして使います。

C#
public class PlayerController : MonoBehaviour
{
public int hp = 100;
}

このPlayerControllerクラスは、プレイヤーの動きや状態を管理する設計図です。これをPlayerというGameObjectにアタッチすると、そのGameObjectがプレイヤーとしての機能を持ちます。

初心者は、クラスやオブジェクトを抽象的に理解しようとしすぎると難しく感じます。まずは「スクリプトはGameObjectに機能を追加する部品」と考えると分かりやすいです。

3-6. public・privateの違いとInspector表示

C#では、変数やメソッドにpublicprivateを付けて、外部からアクセスできるかどうかを指定します。

C#
public float speed = 5.0f;
private int hp = 100;

publicにした変数は、UnityのInspectorに表示されます。Inspectorから値を変更できるため便利です。

ただし、何でもpublicにすると、他のスクリプトから自由に変更できてしまい、バグの原因になることがあります。

そこでよく使うのがSerializeFieldです。

C#
[SerializeField] private float speed = 5.0f;

この書き方なら、変数はprivateのままInspectorに表示できます。Unity開発では、安全に値を調整するためによく使われます。

4. Unity開発で必須のC#スクリプト構造

4-1. MonoBehaviourとは何か

MonoBehaviourは、UnityのC#スクリプトで非常に重要なクラスです。

UnityでGameObjectにアタッチするスクリプトは、多くの場合MonoBehaviourを継承します。

C#
public class PlayerController : MonoBehaviour
{
}

MonoBehaviourを継承することで、Start()Update()OnCollisionEnter()OnTriggerEnter()など、Unity特有のメソッドを使えるようになります。

つまり、MonoBehaviourは「UnityのGameObject上で動くスクリプトに必要な土台」です。

4-2. Start()とUpdate()の役割

Start()は、ゲーム開始時に一度だけ呼ばれるメソッドです。

C#
void Start()
{
Debug.Log("初期化処理");
}

初期スコアの設定、コンポーネントの取得、初期位置の保存などに使います。

一方、Update()は毎フレーム呼ばれます。

C#
void Update()
{
Debug.Log("毎フレーム処理");
}

キーボード入力の確認、キャラクターの移動、時間経過の処理などに使います。

初心者は、次のように覚えると分かりやすいです。

  • Start():最初に一回だけ行う処理

  • Update():ゲーム中にずっと確認し続ける処理

4-3. GameObjectとComponentの関係

Unityでは、画面上にあるキャラクター、カメラ、ライト、アイテムなどはGameObjectです。

ただし、GameObjectだけでは具体的な機能を持ちません。機能はComponentとして追加されます。

たとえば、プレイヤーのGameObjectには次のようなComponentが付くことがあります。

  • Transform:位置・回転・大きさを管理する

  • SpriteRenderer:2D画像を表示する

  • Rigidbody:物理演算を行う

  • Collider:当たり判定を行う

  • C# Script:独自の動きを追加する

Unity開発では、「GameObjectは入れ物、Componentは機能」と考えると理解しやすいです。

4-4. transformで位置・回転・拡大縮小を操作する

transformは、GameObjectの位置、回転、大きさを管理するComponentです。

位置を変更するには、transform.positionを使います。

C#
transform.position = new Vector3(0, 1, 0);

毎フレーム少しずつ移動させるには、次のように書きます。

C#
void Update()
{
transform.position += new Vector3(1, 0, 0) * Time.deltaTime;
}

Time.deltaTimeは、前のフレームからの経過時間です。これを使うことで、PCの性能によって移動速度が変わりにくくなります。

回転にはtransform.Rotate()、拡大縮小にはtransform.localScaleを使います。

C#
transform.Rotate(0, 90 * Time.deltaTime, 0);
transform.localScale = new Vector3(2, 2, 2);

4-5. GetComponentで他の機能を取得する

GetComponentは、同じGameObjectに付いているComponentを取得するためのメソッドです。

たとえば、Rigidbodyを取得する場合は次のように書きます。

C#
private Rigidbody rb;

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

取得したRigidbodyを使えば、物理演算による移動やジャンプを実装できます。

C#
rb.AddForce(Vector3.up * 5.0f, ForceMode.Impulse);

GetComponentで取得できるのは、そのGameObjectに実際に付いているComponentだけです。付いていないComponentを取得しようとするとnullになるため、NullReferenceExceptionの原因になります。

4-6. SerializeFieldを使って安全にInspector編集する

Unityでは、Inspectorから値を調整できると開発が楽になります。

たとえば、移動速度をコードに直接書いていると、変更するたびにスクリプトを編集しなければなりません。

C#
[SerializeField] private float moveSpeed = 5.0f;

このように書くと、moveSpeedprivateのままInspectorに表示されます。

ゲーム開発では、速度、ジャンプ力、HP、スコア加算値、カメラ距離など、何度も調整する値をSerializeFieldにしておくと便利です。

5. 実践:C#でキャラクターを動かす基本手順

5-1. キーボード入力を取得する

Unityでキーボード入力を取得する基本は、Input.GetAxisInput.GetKeyDownです。

左右移動には、次のようにInput.GetAxisを使えます。

C#
float horizontal = Input.GetAxis("Horizontal");

Horizontalは、左キーや右キー、AキーやDキーの入力を取得します。左なら-1、右なら1、入力がなければ0に近い値になります。

スペースキーが押された瞬間を取得するには、次のように書きます。

C#
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("スペースキーが押されました");
}

移動のように押している間ずっと処理したい場合と、ジャンプのように押した瞬間だけ処理したい場合で使い分けることが大切です。

5-2. Transformを使ってオブジェクトを移動させる

Transformを使った移動は、初心者にとって最も分かりやすい方法です。

C#
using UnityEngine;

public class PlayerMove : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5.0f;

void Update()
{
float horizontal = Input.GetAxis("Horizontal");
Vector3 movement = new Vector3(horizontal, 0, 0);
transform.position += movement * moveSpeed * Time.deltaTime;
}
}

このスクリプトをプレイヤーにアタッチすると、左右キーまたはA/Dキーで移動できます。

Transform移動はシンプルですが、物理演算を使った当たり判定とは相性が悪い場合があります。壁にぶつかる、床の上を自然に動く、ジャンプするなどの処理では、Rigidbodyを使う方が適していることがあります。

5-3. Rigidbodyを使った物理ベースの移動

Rigidbodyを使うと、Unityの物理演算に従ってオブジェクトを動かせます。

2DゲームならRigidbody2D、3DゲームならRigidbodyを使います。

3Dの場合の基本例は次のとおりです。

C#
using UnityEngine;

public class RigidbodyMove : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5.0f;
private Rigidbody rb;

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

void FixedUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");

Vector3 movement = new Vector3(horizontal, 0, vertical);
rb.linearVelocity = new Vector3(
movement.x * moveSpeed,
rb.linearVelocity.y,
movement.z * moveSpeed
);
}
}

物理演算を使う処理は、Update()ではなくFixedUpdate()に書くのが基本です。FixedUpdate()は物理演算の更新タイミングに合わせて呼ばれるため、Rigidbody操作に向いています。

5-4. ジャンプ処理をC#で実装する

ジャンプを実装するには、Rigidbodyに上方向の力を加えます。

C#
using UnityEngine;

public class PlayerJump : MonoBehaviour
{
[SerializeField] private float jumpPower = 5.0f;
private Rigidbody rb;
private bool isGrounded = true;

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

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

void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
}

この例では、地面にいるときだけジャンプできるようにしています。地面のGameObjectにはGroundタグを付けておきます。

ジャンプ処理でよくある失敗は、地面判定を入れずに何度でも空中ジャンプできてしまうことです。最初は簡単なisGroundedを使った判定から始めるとよいでしょう。

5-5. カメラ追従の基本を作る

プレイヤーをカメラで追いかけるには、カメラ用のスクリプトを作ります。

C#
using UnityEngine;

public class CameraFollow : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private Vector3 offset = new Vector3(0, 3, -6);

void LateUpdate()
{
transform.position = target.position + offset;
}
}

このスクリプトをMain Cameraにアタッチし、Inspectorのtargetにプレイヤーを設定します。

カメラ追従はUpdate()でも動きますが、プレイヤーの移動が終わった後にカメラ位置を更新したい場合はLateUpdate()を使うと安定しやすいです。

5-6. よくある動かない原因と確認ポイント

キャラクターが動かないときは、次の点を確認しましょう。

まず、スクリプトが正しいGameObjectにアタッチされているか確認します。スクリプトを作っただけでは動きません。

次に、Consoleにエラーが出ていないか確認します。C#にエラーがあると、スクリプト全体が正しく動かないことがあります。

また、Rigidbodyを使うコードなのに、GameObjectにRigidbodyが付いていないこともよくあります。GetComponent<Rigidbody>()を使っている場合は、対象のGameObjectにRigidbodyが必要です。

InspectorでmoveSpeedが0になっている場合も、移動していないように見えます。SerializeFieldで表示されている値も確認しましょう。

6. 当たり判定・アイテム・スコアをC#で実装する

6-1. ColliderとTriggerの違い

Unityで当たり判定を行うには、Colliderを使います。

Colliderは、オブジェクト同士がぶつかったかどうかを判定するためのComponentです。

通常のColliderは、物理的にぶつかります。たとえば、プレイヤーが壁に当たると止まるような処理です。

一方、Triggerは、物理的にはぶつからず、通り抜けながら接触を検知します。アイテム取得やゴール判定によく使います。

ColliderのIs Triggerにチェックを入れると、Triggerとして扱われます。

6-2. OnCollisionEnterとOnTriggerEnterの使い方

通常の衝突を検知するには、OnCollisionEnterを使います。

C#
void OnCollisionEnter(Collision collision)
{
Debug.Log("ぶつかりました");
}

Triggerとの接触を検知するには、OnTriggerEnterを使います。

C#
void OnTriggerEnter(Collider other)
{
Debug.Log("トリガーに入りました");
}

アイテム取得では、OnTriggerEnterを使うことが多いです。プレイヤーがアイテムに触れたら、アイテムを消してスコアを増やす処理を実行します。

6-3. アイテム取得処理を作る

アイテム取得の基本コードは次のようになります。

C#
using UnityEngine;

public class Item : MonoBehaviour
{
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
Destroy(gameObject);
}
}
}

このスクリプトをアイテムにアタッチし、アイテムのColliderのIs Triggerにチェックを入れます。プレイヤー側にはPlayerタグを付けておきます。

Destroy(gameObject)は、このスクリプトが付いているGameObjectを削除する処理です。つまり、プレイヤーが触れたアイテムが消えます。

6-4. スコアを加算して画面に表示する

スコア管理は、専用のスクリプトに分けると扱いやすくなります。

C#
using UnityEngine;
using TMPro;

public class ScoreManager : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI scoreText;
private int score = 0;

public void AddScore(int amount)
{
score += amount;
scoreText.text = "Score: " + score;
}
}

アイテム側からスコアを加算する場合は、ScoreManagerを呼び出します。

C#
using UnityEngine;

public class ScoreItem : MonoBehaviour
{
[SerializeField] private int point = 1;
[SerializeField] private ScoreManager scoreManager;

void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
scoreManager.AddScore(point);
Destroy(gameObject);
}
}
}

初心者は、まずInspectorでScoreManagerを設定する方法から始めると分かりやすいです。慣れてきたら、シングルトンやイベントを使った管理方法も学ぶとよいでしょう。

6-5. ゲームオーバー判定を実装する

ゲームオーバー判定は、プレイヤーのHPや落下位置などを条件にして作ります。

たとえば、プレイヤーが一定の高さより下に落ちたらゲームオーバーにするコードです。

C#
using UnityEngine;

public class GameOverCheck : MonoBehaviour
{
[SerializeField] private float gameOverY = -10.0f;

void Update()
{
if (transform.position.y < gameOverY)
{
Debug.Log("ゲームオーバー");
}
}
}

HPが0になったらゲームオーバーにする場合は、次のように書けます。

C#
public class PlayerHealth : MonoBehaviour
{
[SerializeField] private int hp = 3;

public void Damage(int amount)
{
hp -= amount;

if (hp <= 0)
{
Debug.Log("ゲームオーバー");
}
}
}

最初はConsoleに表示するだけでも十分です。その後、ゲームオーバー画面を表示したり、リトライボタンを作ったりして発展させましょう。

7. Unity初心者がよく遭遇するC#エラーと解決方法

7-1. NullReferenceExceptionの原因と直し方

NullReferenceExceptionは、Unity初心者が特によく見るエラーです。

これは、「存在しないものを使おうとした」ときに発生します。

たとえば、次のようなコードでRigidbodyが付いていない場合、rbnullになります。

C#
private Rigidbody rb;

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

void Update()
{
rb.AddForce(Vector3.up);
}

この状態でrb.AddForceを呼ぶと、NullReferenceExceptionが発生します。

対処法は次のとおりです。

  • 対象のGameObjectに必要なComponentが付いているか確認する

  • Inspectorで変数に参照を設定しているか確認する

  • GetComponentの対象が正しいか確認する

  • エラー文に表示されたスクリプト名と行番号を見る

エラーが出たら、まずConsoleのメッセージを読む習慣をつけましょう。

7-2. The name does not exist in the current contextの対処法

The name does not exist in the current contextは、「その名前は現在の場所では存在しません」という意味です。

よくある原因は、変数名の打ち間違いです。

C#
int score = 0;
scroe += 1;

この例では、scorescroeと打ち間違えています。

また、変数を宣言した場所の外で使おうとした場合にも発生します。

C#
void Start()
{
int hp = 100;
}

void Update()
{
hp -= 1;
}

この場合、hpStart()の中だけで使える変数なので、Update()では使えません。複数のメソッドで使いたい変数は、クラスの中に書きます。

C#
private int hp = 100;

void Update()
{
hp -= 1;
}

7-3. CS1002やCS1513など構文エラーの見つけ方

C#の構文エラーでは、CS1002CS1513のようなコードが表示されます。

CS1002は、主にセミコロン;の付け忘れです。

C#
int score = 0

正しくは次のように書きます。

C#
int score = 0;

CS1513は、波括弧}が足りないときによく出ます。

C#
void Start()
{
Debug.Log("Hello");

正しくは次のように閉じます。

C#
void Start()
{
Debug.Log("Hello");
}

構文エラーは、エラーが出ている行そのものではなく、その少し前に原因があることも多いです。セミコロン、波括弧、丸括弧、ダブルクォーテーションを重点的に確認しましょう。

7-4. Inspectorに変数が表示されない原因

Inspectorに変数が表示されない場合は、次の原因が考えられます。

private変数は、そのままではInspectorに表示されません。

C#
private float speed = 5.0f;

表示したい場合は、publicにするか、SerializeFieldを付けます。

C#
[SerializeField] private float speed = 5.0f;

また、プロパティは通常Inspectorに表示されません。

C#
public int Score { get; set; }

UnityのInspectorに表示したい値は、基本的にフィールドとして書きます。

さらに、スクリプトにコンパイルエラーがあるとInspectorの表示が更新されないことがあります。まずConsoleのエラーを解消しましょう。

7-5. スクリプトを変更しても反映されないときの確認項目

スクリプトを変更したのにUnity上で反映されない場合は、次の点を確認します。

まず、コードエディタで保存しているか確認します。保存していない変更はUnityに反映されません。

次に、Consoleにエラーが出ていないか確認します。C#のエラーが1つでもあると、スクリプト全体のコンパイルが止まることがあります。

また、同じ名前のスクリプトや古いスクリプトを別のGameObjectにアタッチしている場合もあります。Hierarchyで対象のGameObjectを選び、Inspectorに付いているスクリプトを確認しましょう。

Playモード中にInspectorで値を変更した場合、Playモードを終了すると元に戻ることがあります。設定を保存したい場合は、Playモードを止めてから変更しましょう。

8. C# for Unityを効率よく学ぶ実践ロードマップ

8-1. まず覚えるべきC#文法の優先順位

Unity初心者が最初に覚えるべきC#文法は、すべてではありません。優先順位をつけることが大切です。

まずは、変数、if文、メソッド、クラス、配列やリストの基本を覚えましょう。

特に重要なのは次の項目です。

  • 変数と型

  • if文

  • for文

  • メソッド

  • クラス

  • publicとprivate

  • List

  • nullの考え方

これらを理解できれば、簡単なUnityゲームは作れるようになります。

逆に、最初から高度な設計パターン、非同期処理、LINQ、デリゲートなどを完璧に理解しようとする必要はありません。必要になったタイミングで学べば十分です。

8-2. 小さなゲームを作りながら学ぶ理由

C# for Unityを学ぶなら、文法書を読むだけでなく、小さなゲームを作りながら学ぶのが最も効果的です。

おすすめは、次のような小規模ゲームです。

  • 2D横スクロールアクション

  • コイン集めゲーム

  • ブロック崩し

  • シンプルな避けゲーム

  • クリックでスコアが増えるゲーム

小さなゲームでも、移動、当たり判定、スコア、UI、ゲームオーバーなど、Unity開発に必要な基本要素が含まれています。

完成までの範囲が小さいほど、挫折しにくくなります。最初は見た目にこだわりすぎず、「動くものを完成させる」ことを優先しましょう。

8-3. 写経だけで終わらせない学習方法

チュートリアルのコードをそのまま写すだけでは、なかなか自分で書けるようになりません。

写経した後は、必ず少し変更してみましょう。

たとえば、次のような変更がおすすめです。

  • 移動速度を変える

  • ジャンプ力を変える

  • スコアの加算値を変える

  • アイテムを取ったときの音を追加する

  • 敵に当たったらHPを減らす

  • 一定スコアでクリアにする

小さな改造を繰り返すことで、「このコードを変えるとゲームがどう変わるのか」が理解できるようになります。

エラーが出ても問題ありません。エラーを読んで直す経験こそが、UnityのC#学習では非常に重要です。

8-4. 2Dゲームから始めるべきか3Dゲームから始めるべきか

初心者には、2Dゲームから始めるのがおすすめです。

2Dゲームは、考える軸が少ないため、移動や当たり判定を理解しやすいです。左右移動、ジャンプ、アイテム取得など、UnityとC#の基本を学ぶには十分です。

ただし、3Dゲームを作りたい明確な目的があるなら、最初から3Dでも構いません。その場合は、カメラ、奥行き、物理演算、座標の扱いで少し難しく感じる場面が増えます。

大切なのは、自分が作りたいものに近い題材を選ぶことです。興味のない題材で学ぶより、多少難しくても作りたいゲームに挑戦する方が継続しやすいです。

8-5. 脱初心者に必要な次の学習テーマ

基本的なC# for Unityに慣れてきたら、次のテーマに進みましょう。

まず学びたいのは、シーン管理です。タイトル画面、ゲーム画面、リザルト画面を切り替えられるようになると、ゲームらしさが大きく増します。

次に、UI制御です。スコア、HPバー、ボタン、メニュー画面などをC#で操作できるようになると、プレイヤーに分かりやすいゲームを作れます。

さらに、Prefabの使い方も重要です。敵や弾、アイテムをPrefab化して生成できるようになると、ゲームの幅が広がります。

その後は、次のようなテーマに進むとよいでしょう。

  • アニメーション制御

  • サウンド再生

  • ScriptableObject

  • セーブとロード

  • オブジェクトプール

  • 簡単な設計パターン

  • Input System

  • ゲーム全体の状態管理

ここまで学べば、初心者向けチュートリアルをなぞる段階から、自分でゲームを設計して作る段階へ進めます。

まとめ

CSharp for Unityを学ぶときに大切なのは、C#の文法だけを単独で覚えようとしないことです。Unityでは、C#スクリプトをGameObjectにアタッチし、Transform、Rigidbody、Collider、Componentなどの仕組みと組み合わせてゲームを作ります。

初心者はまず、変数、if文、繰り返し、メソッド、クラス、publicとprivateなどの基本文法を押さえましょう。そのうえで、Start()Update()MonoBehaviourGetComponentSerializeFieldなど、Unity特有の書き方に慣れていくことが重要です。

最初から完璧なコードを書く必要はありません。キャラクターを動かす、ジャンプする、アイテムを取る、スコアを増やすといった小さな機能を一つずつ作ることで、C# for Unityの理解は確実に深まります。

エラーが出たときも、Consoleのメッセージを読み、原因を一つずつ確認すれば解決できます。特に、NullReferenceException、変数名のミス、セミコロンや波括弧の不足は初心者がよく経験するポイントです。

UnityのC#学習は、実際に手を動かしてゲームを作るほど上達します。小さなゲームを完成させながら、少しずつ機能を追加し、自分で考えて改造することが、脱初心者への一番の近道です。