質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

[Unity]GetComponentが上手くいきません

受付中

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 6,734

score 17

初投稿で何か不足があったら申し訳ございません。
Unityチュートリアルでローグライクゲームを作ろうとしています。(参考https://unity3d.com/jp/learn/tutorials/projects/2d-roguelike-tutorial/writing-game-manager?playlist=17150)

GameManagerオブジェクトにBoardManagerスクリプトとGameManagerスクリプトをアタッチして、GameManagerスクリプトからBoardManagerスクリプトの中にあるSetupScene()というメソッドを取り出そうとしているのですが、Unity側から参照できないと言われてしまいます。スクリプト自体はコピペでも試しているので間違いないと思います。

このチュートリアルを日本語で解説してくださっているサイトに載っていた同じ過程のInspectorの画像が
イメージ説明こうなっているのに対して自分のは
イメージ説明こうなっています

たぶんGetComponentする前にGameManagerスクリプトでpublic BoardManager boardScript;と記述しているのでこれが自分の場合変数扱いになっているのでは? と考えています。

すいません、ご教授願います。三日も次に進めない状況です。

発生している問題・エラーメッセージ

NullReferenceException: Object reference not set to an instance of an object
GameManager.InitGame () (at Assets/Scripts/GameManager.cs:19)
GameManager.Awake () (at Assets/Scripts/GameManager.cs:14)

該当のソースコード

```C#
【BoardManagerスクリプト】
using UnityEngine;
using System;
//Listを使うため
using System.Collections.Generic;
//Randomを使うため
using Random = UnityEngine.Random;

public class BoardManager : MonoBehaviour {
//カウント用のクラスを設定
[Serializable]
public class Count {
public int minimum;
public int maximum;

public Count (int min, int max) {
minimum = min;
maximum = max;
}
}

//8*8のゲームボードを作るので縦の段を8、横の列を8
public int columns = 8;
public int rows = 8;
//壁は5〜9の間で出現
public Count wallCount = new Count (5,9);
//アイテムは1〜5の間で出現
public Count foodCount = new Count (1,5);
//Exitは単体
public GameObject exit;
//床・内壁・アイテム・敵キャラ・外壁は複数あるため配列
public GameObject[] floorTiles;
public GameObject[] wallTiles;
public GameObject[] foodTiles;
public GameObject[] enemyTiles;
public GameObject[] outerWallTiles;
//オブジェクトの位置情報を保存する変数
private Transform boardHolder;
//オブジェクトを配置できる範囲を表すリスト
//Listは可変型の配列
private List <Vector3> gridPositions = new List<Vector3>();

//敵キャラ・アイテム・内壁を配置できる範囲を決定
void InitialiseList ()
{
//gridPositionをクリア
gridPositions.Clear ();
//gridPositionにオブジェクト配置可能範囲を指定
//x = 1〜6をループ
for (int x = 1; x < columns - 1; x++) {
//y = 1〜6をループ
for (int y = 1; y < rows - 1; y++) {
//6*6の範囲をgridPositionsに指定
gridPositions.Add(new Vector3(x, y, 0f));
}
}
}
//外壁、床を配置
void BoardSetup ()
{
//Boardというオブジェクトを作成し、transform情報をboardHolderに保存
boardHolder = new GameObject ("Board").transform;
//x = -1〜8をループ
for (int x = -1; x < columns + 1; x++) {
//y = -1〜8をループ
for (int y = -1; y < rows + 1; y++) {
//床をランダムで選択
GameObject toInstantiate = floorTiles [Random.Range (0, floorTiles.Length)];
//左端or右端or最低部or最上部の時=外壁を作る時
if (x == -1 || x == columns || y == -1 || y == rows) {
//floorTileの時と同じように外壁をランダムで選択し、上書きする
toInstantiate = outerWallTiles [Random.Range (0, outerWallTiles.Length)];
}
//床or外壁を生成し、instance変数に格納
GameObject instance = Instantiate(toInstantiate, new Vector3(x, y, 0f),
Quaternion.identity) as GameObject;
//生成したinstanceをBoardオブジェクトの子オブジェクトとする
instance.transform.SetParent(boardHolder);
}
}
}

Vector3 RandomPosition () {
//0〜36からランダムで1つ決定し、位置情報を確定
int randomIndex = Random.Range(0, gridPositions.Count);
Vector3 randomPosition = gridPositions[randomIndex];
//ランダムで決定した数値は削除
gridPositions.RemoveAt(randomIndex);
//確定した位置情報を返す
return randomPosition;
}

void LayoutObjectAtRandom (GameObject[] tileArray, int minimum, int maximum)
{
//最低値〜最大値+1のランダム回数分だけループ
int objectCount = Random.Range (minimum, maximum + 1);
for (int i = 0; i < objectCount; i++) {
//gridPositionから位置情報を1つ取得
Vector3 randomPosition = RandomPosition();
//引数tileArrayからランダムで1つ選択
GameObject tileChoise = tileArray[Random.Range(0, tileArray.Length)];
//ランダムで決定した種類・位置でオブジェクトを生成
Instantiate (tileChoise, randomPosition, Quaternion.identity);
}
}
//オブジェクトを配置していくメソッド
//このクラス内唯一のpublicメソッド 床を生成するタイミングでGameManagerから呼ばれる
public void SetupScene (int level)
{
//床と外壁を配置し、
BoardSetup();
//敵キャラ・内壁・アイテムを配置できる位置を決定し、
InitialiseList();
//内壁・アイテム・敵キャラをランダムで配置し、
LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);
LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum);
//Mathf.Log : 対数で計算。level=2なら4、level=3なら8
int enemyCount = (int)Mathf.Log(level, 2f);
LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);
//Exitを7, 7の位置に配置する。
Instantiate(exit, new Vector3(columns - 1, rows - 1, 0F), Quaternion.identity);
}
}

【GameManagerスクリプト】
using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {

public BoardManager boardScript;
//テストとしてレベルを3にしておく
private int level = 3;

//Awake : Sceneを移動した時即座に実行される
void Awake () {
//BoardManager取得
boardScript = GetComponent<BoardManager>();
InitGame();
}

void InitGame () {
//BoardManagerのSetupSceneメソッドを実行
boardScript.SetupScene(level);
}
}

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

0

  1. GameManagerおよびBoardManagerのスクリプトを作成
  2. HierarchyにGameManagerゲームオブジェクトを作り、上記 2 スクリプトをアタッチ。
  3. 実行してデバッグログが流れていることを確認

参照が通るか試すためだけにざっくり簡略化したスクリプトで試してみましたが特に問題なく
BoardManagerのSetupSceneが呼ばれ、デバッグログが表示されました。

boardScript は BoardManager 型で宣言された変数です。publicがついているのでインスペクター上にも表示されています。
そして、GameManagerは、GameManager.csとBoardManager.csの2つがアタッチされているので
GetComponent<BoardManager>() にて自身にアタッチされた BoardManager コンポーネントを参照してさっき宣言しておいたboardScriptに参照先を入れています。

極端な話、boardScriptを使わずに GetComponent<BoardManger>().SetupScene(level);とか書いてもメソッドは呼べます。

とりあえず、本来の処理は一旦おいといて各所にデバッグログを入れて参照がnullになってないか。nullになってるとしたらどこなのかを探してみてはいかがでしょうか。

【GameManager】

using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {

    public BoardManager boardScript;
    //テストとしてレベルを3にしておく
    private int level = 3;

    //Awake : Sceneを移動した時即座に実行される
    void Awake() {
        //BoardManager取得
        boardScript = GetComponent<BoardManager>();

        Debug.Log("GetComponent<BoardManager> : " + boardScript); // 参照が取れているか?

        InitGame();
    }

    void InitGame() {
        //BoardManagerのSetupSceneメソッドを実行
        boardScript.SetupScene(level);

    }
}

【BoardManager】(簡略化)

using UnityEngine;
using System;
//Listを使うため
using System.Collections.Generic;
//Randomを使うため
using Random = UnityEngine.Random;

public class BoardManager : MonoBehaviour {
    //カウント用のクラスを設定
    [Serializable]
    public class Count {
        public int minimum;
        public int maximum;

        public Count(int min, int max) {
            minimum = min;
            maximum = max;
        }
    }

    //8*8のゲームボードを作るので縦の段を8、横の列を8
    public int columns = 8;
    public int rows = 8;
    //壁は5〜9の間で出現
    public Count wallCount = new Count(5, 9);
    //アイテムは1〜5の間で出現
    public Count foodCount = new Count(1, 5);
    //Exitは単体
    public GameObject exit;
    //床・内壁・アイテム・敵キャラ・外壁は複数あるため配列
    public GameObject[] floorTiles;
    public GameObject[] wallTiles;
    public GameObject[] foodTiles;
    public GameObject[] enemyTiles;
    public GameObject[] outerWallTiles;
    //オブジェクトの位置情報を保存する変数
    private Transform boardHolder;
    //オブジェクトを配置できる範囲を表すリスト
    //Listは可変型の配列
    private List<Vector3> gridPositions = new List<Vector3>();

    //敵キャラ・アイテム・内壁を配置できる範囲を決定
    void InitialiseList() {
        //gridPositionをクリア
        gridPositions.Clear();
        //gridPositionにオブジェクト配置可能範囲を指定
        //x = 1〜6をループ
        for (int x = 1; x < columns - 1; x++) {
            //y = 1〜6をループ
            for (int y = 1; y < rows - 1; y++) {
                //6*6の範囲をgridPositionsに指定
                gridPositions.Add(new Vector3(x, y, 0f));
            }
        }
    }
    //外壁、床を配置
    void BoardSetup() {
        //Boardというオブジェクトを作成し、transform情報をboardHolderに保存
        boardHolder = new GameObject("Board").transform;
        //x = -1〜8をループ
        for (int x = -1; x < columns + 1; x++) {
            //y = -1〜8をループ
            for (int y = -1; y < rows + 1; y++) {
                //床をランダムで選択
                GameObject toInstantiate = floorTiles[Random.Range(0, floorTiles.Length)];
                //左端or右端or最低部or最上部の時=外壁を作る時
                if (x == -1 || x == columns || y == -1 || y == rows) {
                    //floorTileの時と同じように外壁をランダムで選択し、上書きする
                    toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];
                }
                //床or外壁を生成し、instance変数に格納
                GameObject instance = Instantiate(toInstantiate, new Vector3(x, y, 0f),
                Quaternion.identity) as GameObject;
                //生成したinstanceをBoardオブジェクトの子オブジェクトとする
                instance.transform.SetParent(boardHolder);
            }
        }
    }

    Vector3 RandomPosition() {
        //0〜36からランダムで1つ決定し、位置情報を確定
        int randomIndex = Random.Range(0, gridPositions.Count);
        Vector3 randomPosition = gridPositions[randomIndex];
        //ランダムで決定した数値は削除
        gridPositions.RemoveAt(randomIndex);
        //確定した位置情報を返す
        return randomPosition;
    }

    void LayoutObjectAtRandom(GameObject[] tileArray, int minimum, int maximum) {
        //最低値〜最大値+1のランダム回数分だけループ
        int objectCount = Random.Range(minimum, maximum + 1);
        for (int i = 0; i < objectCount; i++) {
            //gridPositionから位置情報を1つ取得
            Vector3 randomPosition = RandomPosition();
            //引数tileArrayからランダムで1つ選択
            GameObject tileChoise = tileArray[Random.Range(0, tileArray.Length)];
            //ランダムで決定した種類・位置でオブジェクトを生成
            Instantiate(tileChoise, randomPosition, Quaternion.identity);
        }
    }
    //オブジェクトを配置していくメソッド
    //このクラス内唯一のpublicメソッド 床を生成するタイミングでGameManagerから呼ばれる
    public void SetupScene(int level) {

        // とりあえずデバッグログだけ出してみる
        Debug.Log("Call : SetupScene");
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

scriptにNoneと表示されているのであれば、ヒエラルキーからオブジェクトをそこにドラッグすると良いでしょう。ヒエラルキーのゲームオブジェクトをNone表示されているスクリプト欄にドラッグする

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る