Unityでスクリプトを書いていると、ConsoleにCS0246CS0103といった番号付きのエラーが表示されます。

このCSから始まる番号は、C#コンパイラがエラーの種類を区別するためのコードです。

慣れないと原因を理解するのが大変かもしれませんが、

長い英語メッセージを最初からすべて読むより、まず番号を見ると確認箇所を絞れます。

この記事では、Unity開発で遭遇しやすいコンパイルエラーを、エラーになるコードと修正後のコードを並べて説明します。

探している番号やメッセージをページ内検索すれば、該当する項目へ直接移動できます。

Consoleウィンドウの開き方、絞り込み、ファイルと行番号の確認方法は別の記事で解説しています。

記事末尾の関連ページから参照してください。

よくあるコンパイルエラー早見表

エラー主な原因
CS0246型、名前空間、パッケージが見つからない
CS0103変数名やメソッド名が現在のスコープに存在しない
CS1061対象の型に指定したメンバーがない
CS0029代入元と代入先の型が一致していない
CS0117型に指定した静的メンバーがない
CS0120インスタンスが必要なメンバーを型から呼んでいる
CS0019指定した型の組み合わせでは演算子を使用できない
CS0234名前空間内に指定した型や名前空間がない
CS1002セミコロンが不足している
CS1513閉じ波括弧が不足している

表の「主な原因」は、最初に調べる場所を示したものです。同じ番号でも、メッセージ内の型名やメンバー名はコードによって変わります。

まずエラー番号とメッセージ内の型名・メンバー名を、手元の表示と照合してください。一致したら、失敗例とコードを比べ、原因に合う確認項目を順に追います。

CS0246: The type or namespace name could not be found

CS0246は、コードに書かれた型または名前空間をC#コンパイラが見つけられないときに発生します。

Unityのクラスを使うコードでは、スペルが合っていてもusingやパッケージ、アセンブリ参照が不足していると型を解決できません。

正式なメッセージはThe type or namespace name could not be found (are you missing a using directive or an assembly reference?)です。

実際のConsoleでは、見つからなかった型名や名前空間名も表示されます。まず、その名前をコード内の宣言やAPIリファレンスと照合します。

次のコードでは、Rigidbodyが属するUnityEngine名前空間を読み込んでいないためエラーになります。

// using UnityEngine; がないためRigidbodyを解決できない
public class PlayerMover
{
    private Rigidbody _body;
}

ファイルの先頭にusing UnityEngine;を追加すると、Rigidbodyを解決できます。

using UnityEngine;

public class PlayerMover
{
    private Rigidbody _body;
}

代表的な原因は次の5つです。

  1. 型名または名前空間名のスペルや大文字・小文字が違う
  2. 型が属する名前空間のusingがない
  3. 型を提供するパッケージがプロジェクトに入っていない
  4. asmdefから、その型を含むアセンブリを参照していない
  5. 使用中のUnityやパッケージのバージョンに、そのAPIが存在しない

確認する順番は「スペル → usingPackage Managerasmdef → APIのバージョン差」です。

まずコードだけで直せる箇所を確認し、その後にプロジェクトの依存関係を追うと原因を絞りやすくなります。

usingを書いても消えない場合、同名のクラスを作る必要はありません。

型を提供するパッケージがあるか、そのアセンブリを現在のasmdefから参照できるかを確認します。

古いサンプルを使っているなら、対象APIが使用中のUnityバージョンにも存在するかまで見ます。

CS0103: The name does not exist in the current context

CS0103は、変数名やメソッド名などが現在のコンテキストから参照できないときに発生します。

宣言そのものがあっても、使う場所が宣言のスコープ外なら参照できません。

正式なメッセージはThe name 'identifier' does not exist in the current contextです。

'identifier'の部分には、見つからなかった変数名やメソッド名が入ります。

その名前をそのまま検索すると、宣言と参照のずれを探しやすくなります。

次のscoreStart()内のローカル変数です。参照できる範囲はStart()の波括弧内だけなので、Update()からは見つけられません。

using UnityEngine;

public class ScoreView : MonoBehaviour
{
    private void Start()
    {
        int score = 100;
    }

    private void Update()
    {
        Debug.Log(score); // scoreはStartの外から参照できない
    }
}

複数のメソッドから使う値はフィールドへ移します。これならUpdate()からも_scoreを参照できます。

using UnityEngine;

public class ScoreView : MonoBehaviour
{
    private int _score = 100;

    private void Update()
    {
        Debug.Log(_score);
    }
}

スコープのほかには、スペルミス、変数やメソッドを名前変更した後に古い名前が残っているケースがあります。

#ifなどの条件付きコンパイルで宣言部分だけが除外され、参照側だけが残った場合にも同じエラーが出ます。

エラー行の名前と宣言を照合し、宣言が同じクラスやメソッドのスコープにあるか、現在のビルド条件で有効かを順に確認します。

確認箇所は、名前の一致だけではありません。

  • 大文字・小文字を含めて、宣言と参照のスペルが同じか
  • ローカル変数を、宣言した波括弧の外から使っていないか
  • 名前変更前の参照が別ファイルに残っていないか
  • 宣言側と参照側が、同じ条件付きコンパイルで有効になるか

フィールドへ移した場合は、値をどこで初期化するかも確認します。スコープを広げただけでは、用途に合う値が入るとは限りません。

CS1061: does not contain a definition for

CS1061は、変数の型は見つかっているものの、その型に呼び出したメソッドやプロパティが定義されていないときに発生します。

UnityではGameObjectTransform、各コンポーネントの取り違えがよくある原因です。

正式なメッセージは'type' does not contain a definition for 'name' and no accessible extension method 'name' accepting a first argument of type 'type' could be found (are you missing a using directive or an assembly reference?).です。

'type'が呼び出し元の型、'name'が見つからないメンバーを表します。

次の_playerGameObject型です。positionGameObjectではなくTransformのプロパティなので、直接アクセスできません。

using UnityEngine;

public class PlayerPosition : MonoBehaviour
{
    [SerializeField] private GameObject _player;

    private void Start()
    {
        _player.position = Vector3.zero;
    }
}

GameObjectが持つtransformプロパティを経由して、Transform.positionへアクセスします。

using UnityEngine;

public class PlayerPosition : MonoBehaviour
{
    [SerializeField] private GameObject _player;

    private void Start()
    {
        _player.transform.position = Vector3.zero;
    }
}

まず変数の宣言やIDEの型表示を見て、メンバーを呼び出している対象がGameObjectなのか、Transformなのか、別のコンポーネントなのかを確認します。GetComponent<T>()を使っている場合は、Tに指定した型と代入先の型も確認してください。

型が正しければ、メンバー名のスペルと大文字・小文字を見直します。拡張メソッドだけが見つからない場合は、その拡張メソッドを定義した名前空間のusingやアセンブリ参照を確認します。

古い記事のコードを写した場合は、UnityやパッケージのAPI差によってメンバーが改名・削除されていないかも確認します。

切り分けるときは、エラー文に出た'type'から見ます。想定した型と違えば、変数の宣言、メソッドの戻り値、GetComponent<T>()Tをたどります。型が合っているなら、次に'name'のスペルとAPIのバージョンを調べます。

拡張メソッドの場合だけは、その型の本来のメンバーでなくても呼び出せます。

必要なusingとアセンブリ参照がそろっていないと候補に現れないため、型と名前が正しいのに見つからないときの確認対象です。

CS0029: Cannot implicitly convert type

CS0029は、代入元の値を代入先の型へ暗黙的に変換できないときに発生します。

Unityでは、GameObjectTransformComponentを取り違えたときによく見かけます。

正式なメッセージはCannot implicitly convert type 'type' to 'type'です。

先に表示される型が代入元、後に表示される型が代入先です。エラー文だけでも、代入式の左右で食い違っている型を確認できます。

次のコードでは、GetComponent<Rigidbody>()が返すRigidbodyGameObject型の_playerへ代入しています。

RigidbodyからGameObjectへの暗黙的な変換はないため、代入できません。

using UnityEngine;

public class PlayerBody : MonoBehaviour
{
    private GameObject _player;

    private void Awake()
    {
        _player = GetComponent<Rigidbody>();
    }
}

取得したいものがRigidbodyなら、代入先のフィールドもRigidbody型にそろえます。

using UnityEngine;

public class PlayerBody : MonoBehaviour
{
    private Rigidbody _playerBody;

    private void Awake()
    {
        _playerBody = GetComponent<Rigidbody>();
    }
}

まず、代入式の左辺にある変数の型と、右辺のメソッドやプロパティが返す型を確認します。メソッドの戻り値を変更した後、呼び出し側の変数だけが古い型のまま残っているケースもあります。

数値型では、情報が失われる可能性がある変換は自動で行われません。たとえばfloatからintへの変換には明示的なキャストや変換メソッドが必要です。

ただし、キャストを足す前に、小数部分を切り捨ててよいのかを確認してください。型をそろえるべきなのか、意図した明示的変換なのかを判断してから修正します。

Unityのオブジェクトを扱う代入では、次の対応も確認します。

  • GetComponent<Rigidbody>()が返すのはRigidbody
  • gameObjectプロパティから得られるのはGameObject
  • transformプロパティから得られるのはTransform

型名が似ていても、自動では変換されません。必要なオブジェクトを取り直すのか、代入先の宣言を直すのかを、コードの用途から選びます。

CS0117: does not contain a definition for

CS0117は、型名から参照した静的メンバーが、その型に定義されていないときに発生します。

正式なメッセージは'type' does not contain a definition for 'identifier'です。'type'には型名、'identifier'には探したメンバー名が入ります。

次のTime.fixedDeltaというプロパティはUnity APIに存在しません。

using UnityEngine;

public class PhysicsStep : MonoBehaviour
{
    private void Start()
    {
        Debug.Log(Time.fixedDelta);
    }
}

正しいプロパティ名はTime.fixedDeltaTimeです。

using UnityEngine;

public class PhysicsStep : MonoBehaviour
{
    private void Start()
    {
        Debug.Log(Time.fixedDeltaTime);
    }
}

型名の後ろに書いたメンバーのスペルと大文字・小文字を確認します。列挙型なら、指定した列挙値が本当に定義されているかも確認してください。古い記事やサンプルコードを使っている場合は、Unityやパッケージの更新でAPIが改名・削除されていることもあります。使用中のバージョンのAPIリファレンスと照合します。

似たメッセージのCS1061とは、メンバーを探している対象が違います。Time.fixedDeltaのように型名から静的メンバーを探して見つからない場合はCS0117、変数などのインスタンスからメンバーを探して見つからない場合はCS1061です。

エラー行のピリオドより左側を見ると区別できます。

  • Timeのような型名なら、静的メンバーの候補をAPIリファレンスで調べる
  • _playerのような変数なら、その変数の型を確認してCS1061の手順で調べる

候補に近い名前があっても、用途まで同じとは限りません。改名されたAPIか、別の値を返すAPIかを、使用中のUnityバージョンのリファレンスで確かめます。

CS0120: An object reference is required

CS0120は、インスタンスに属するフィールド、メソッド、プロパティへ、インスタンス参照なしでアクセスしたときに発生します。

staticメンバーとインスタンスメンバーの混同が代表的な原因です。

正式なメッセージはAn object reference is required for the non-static field, method, or property 'member'です。

メンバー自体は存在しますが、どのオブジェクトのメンバーを使うのか指定されていません。

次のResetScore()staticメソッドですが、_scoreScoreManagerの各インスタンスが持つフィールドです。

どのインスタンスの_scoreを変更するのか決められないため、コンパイルできません。

using UnityEngine;

public class ScoreManager : MonoBehaviour
{
    private int _score;

    public static void ResetScore()
    {
        _score = 0;
    }
}

この例では、ResetScore()からstaticを外し、同じインスタンスの_scoreを変更するメソッドにします。

using UnityEngine;

public class ScoreManager : MonoBehaviour
{
    private int _score;

    public void ResetScore()
    {
        _score = 0;
    }
}

修正するときは、対象のデータをクラス全体で1つだけ共有したいのか、GameObjectごとに持たせたいのかを先に決めます。

別のGameObjectに付いたコンポーネントのメンバーを操作するなら、そのコンポーネントのインスタンス参照が必要です。

Inspectorから参照を設定するか、GetComponent<T>()などで対象を取得してからインスタンスメンバーを呼び出します。

単にフィールドへstaticを付けるとエラーは消えることがありますが、全インスタンスで値を共有する設計に変わります。

GameObjectごとに別の値を持たせるなら、呼び出し側から対象のScoreManagerを渡すか、コンポーネント参照を取得します。

調べる順番は次のとおりです。

  1. メッセージに出た'member'の宣言を開く
  2. 宣言にstaticがあるか確認する
  3. 呼び出し元がstaticな文脈か、型名からアクセスしていないか確認する
  4. インスタンスが必要なら、その取得方法を決める

CS0019: Operator cannot be applied to operands

CS0019は、演算子と左右のオペランド型の組み合わせが定義されていないときに発生します。

UnityではVector2Vector3と数値型を混ぜた計算で起こりやすいエラーです。

正式なメッセージはOperator 'operator' cannot be applied to operands of type 'type' and 'type'です。

'operator'には使えない演算子、2つの'type'には左辺と右辺の型が表示されます。

次の減算は左辺がVector3、右辺がfloatです。Vector3 - floatという演算子は定義されていません。

using UnityEngine;

public class MoveTarget : MonoBehaviour
{
    private void Start()
    {
        Vector3 target = transform.position - 1f;
    }
}

すべての軸から1ずつ引きたい場合は、右辺もVector3型にします。

using UnityEngine;

public class MoveTarget : MonoBehaviour
{
    private void Start()
    {
        Vector3 target = transform.position - Vector3.one;
    }
}

エラー行では、演算子の左側と右側がそれぞれ何型か、その組み合わせに使える演算子かを確認します。

&&||なら左右にboolとして評価できる式が必要です。比較演算子では、その左右の型を比較できるかを調べます。

確認は次の順番で進めます。

  1. メッセージに表示された演算子をエラー行で探す
  2. 演算子の左辺と右辺の型を確認する
  3. 片方を別の型と取り違えていないか宣言へ戻る
  4. 意図した演算ができる型の組み合わせへ式を直す

なお、代入の=と比較の==を混同したときのエラー番号は、コードの形によって変わります。

必ずCS0019になるわけではないため、このエラーでは表示された演算子と左右の型から原因を追います。

CS0234: does not exist in the namespace

CS0234は、親の名前空間までは解決できているものの、その中に指定した型または子の名前空間が存在しないときに発生します。

型や名前空間全体を見つけられないCS0246に対し、CS0234では「どの名前空間の中を探したか」まではコンパイラが把握しています。

正式なメッセージはThe type or namespace name does not exist in the namespace (are you missing an assembly reference?)です。

Consoleには、見つからない名前と、検索できた親名前空間が表示されます。

たとえばUniversal RP(URP)を導入していないプロジェクトでは、UnityEngine.Renderingまでは解決できても、その下のUniversal名前空間を見つけられません。

using UnityEngine.Rendering.Universal;

public class PipelineCheck
{
}

URPを使わないプロジェクトなら、URP固有の名前空間と型への参照を削除します。

public class PipelineCheck
{
}

URPを使う場合は、エラーを消すためにコードを削除してはいけません。

Package ManagerUniversal RPを導入し、パッケージが提供するアセンブリを利用できる状態にします。

スクリプト側でasmdefを使っているなら、必要に応じてURPのアセンブリ参照も追加してください。

CS0246と迷ったら、メッセージに親名前空間が示されているかを見ます。

  • 親名前空間も含めて名前を解決できないならCS0246の確認順を使う
  • 親名前空間は見つかり、その中の名前だけがないならCS0234として調べる

CS0234では、子名前空間のスペル、パッケージの導入状態、asmdef参照、APIのバージョン差を順に確認します。

CS1002: ; expected

CS1002は、C#の文末に必要なセミコロンがないときに発生します。

正式なメッセージは; expectedです。短いメッセージですが、表示された位置にセミコロンを足せば必ず直る、という意味ではありません。

コンパイラが文の終わりを判断できなくなった位置を示すこともあります。

次のコードでは、変数を宣言した行の末尾にセミコロンがありません。

int score = 100

行末にセミコロンを追加します。

int score = 100;

セミコロンが書かれていても、直前の行で文字列の"や丸括弧の)を閉じ忘れていると、後続の行にCS1002が表示されることがあります。

表示された行だけで原因が見つからなければ、直前の行に閉じ忘れがないか確認してください。

原因を探す範囲は、エラー行から少しずつ前へ広げます。

  1. エラー行の文末に;があるか確認する
  2. 直前の式で)]を閉じているか確認する
  3. 文字列の開始と終了の"が対になっているか確認する
  4. 最初に現れた構文エラーを直してから再コンパイルする

構文が途中で崩れると、後ろの正しい行にもエラーが連鎖します。

複数行へ; expectedが出ても、まとめてセミコロンを追加せず、最初の崩れを探します。

CS1513: } expected

CS1513は、コードブロックを閉じる波括弧の}が不足しているときに発生します。

正式なメッセージは} expectedです。メソッド、クラス、ifなど、{で始めたブロックを閉じられないときに表示されます。

次のコードでは、Start()メソッドを閉じる波括弧がありません。

private void Start()
{
    Debug.Log("Start");

メソッドの末尾に閉じ波括弧を追加します。

private void Start()
{
    Debug.Log("Start");
}

波括弧が何組もあるコードでは、IDEで開き括弧または閉じ括弧にカーソルを合わせ、対応する括弧の強調表示を確認します。

自動整形をかけてインデントが不自然にずれる場所を探す方法もあります。

ファイル末尾にエラーが出た場合も、原因が末尾にあるとは限りません。

上にあるclass、メソッド、条件分岐を順にたどり、開き波括弧と閉じ波括弧が対になっているか確認します。

波括弧を数えるだけで見つからないときは、次の手順で範囲を狭めます。

  • IDEの対応括弧表示で、対にならない{を探す
  • 自動整形後に、インデントが戻らない位置を探す
  • 最初のCS1513より前にある構文エラーを確認する
  • 1か所直すたびに再コンパイルし、残ったエラーを読み直す

All compiler errors have to be fixed before you can enter playmode

このメッセージ自体は、エラーの根本原因ではありません。

コンパイルに失敗しているため、UnityがPlayモードへの移行を止めていることを知らせるメッセージです。

All compiler errors have to be fixed before you can enter playmodeだけを検索しても、壊れているコードは特定できません。

同じタイミングでConsoleに表示されたCSxxxxと、そのメッセージにあるファイル名・行番号を確認します。

次の順番で原因を追います。

  1. 同時に表示されているCSxxxxを探す
  2. 一覧の最初にあるコンパイルエラーから直す
  3. Unityの再コンパイル完了を待つ
  4. エラーが残る場合は次のCSxxxxを確認する

先頭の構文エラーが後続のエラーを引き起こしていることがあります。最初のエラーを直しただけで、残りもまとめて消える場合があります。

修正直後は、Unityがスクリプトを再コンパイルしている間もPlayモードへ入れません。

再コンパイルの完了を待ち、Consoleに残ったCSxxxxをもう一度先頭から確認します。

大量のエラーが出たときも、末尾から直す必要はありません。

;}の不足で構文解析が崩れると、同じファイルの後続行に別のエラーが並ぶためです。最初の1件を直して件数がどう変わるかを見ます。

まとめ

コンパイルエラーが出たら、まずCSxxxxのコードで検索します。

エラーが複数ある場合は、一覧の最初にあるものから直してください。

後続のエラーが連鎖して表示されていることがあるためです。

同じエラーコードでも、実際に間違っている型や変数はコードごとに異なります。

メッセージ内の型名や変数名まで確認すると、調べる場所を絞れます。

型やメンバーが見つからないエラーでは、スペル、using、パッケージ、asmdefの順に確認します。

型の代入や演算で止まったら、式の左右にある型を比べます。; expected} expectedが複数並んだ場合は、最初の構文エラーから直します。

修正後はUnityの再コンパイルを待ち、同じCSxxxxが残っているかを確認してください。

消えていれば次のエラーへ進み、残っていればメッセージ内の型名、メンバー名、行番号を読み直します。