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

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

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

695閲覧

時間経過によって障害物を変化させる方法

unitykun

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2021/03/30 08:28

編集2021/03/31 03:37

前提・実現したいこと

時間経過によって、ブロックの数を増やし、スピードを速くしたいと考えています。
製作途中でエラーが発生したため、解決方法を教えていただきたいです。

この問題が解決した後は、BlockMgrを更に増やしたいと考えています。

発生している問題

一定時間経つと、ブッロクが作れなくなる。
(初めの8秒程度はエラーは発生しません)

エラーコード

MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object. UnityEngine.Object.Internal_InstantiateSingle (UnityEngine.Object data, UnityEngine.Vector3 pos, UnityEngine.Quaternion rot) (at <10564ed154d647e194bef4aef8878649>:0) UnityEngine.Object.Instantiate (UnityEngine.Object original, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation) (at <10564ed154d647e194bef4aef8878649>:0) UnityEngine.Object.Instantiate[T] (T original, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation) (at <10564ed154d647e194bef4aef8878649>:0) BlockMgr2.Update () (at Assets/Scripts/BlockMgr2.cs:51)

該当のソースコード

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class BlockMgr : MonoBehaviour 6{ 7 // 生成するBlockオブジェクト 8 public GameObject block; 9 10 // 0になったらBlockオブジェクトを生成 11 float _timer = 0; 12 // トータルの経過時間を保持 13 float _totalTime = 0; 14 // ①ブロック生成回数 15 int _cnt = 0; 16 17 void Start() 18 { 19 20 } 21 22 void Update() 23 { 24 // 経過時間を差し引く 25 _timer -= Time.deltaTime; 26 // トータル時間を加算 27 _totalTime += Time.deltaTime; 28 29 if (_timer < 0) 30 { 31 // 0になったのでBlock生成 32 // BlockMgrの場所から生成 33 Vector3 position = transform.position; 34 // ※上下(±3)のランダムな位置に出現させる 35 position.y = Random.Range(-3, 5); 36 // プレハブをもとにBlock生成 37 GameObject obj = Instantiate(block, position, Quaternion.identity); 38 // Blockオブジェクトの「Block」スクリプトを取得する 39 Block blockScript = obj.GetComponent<Block>(); 40 // 速度を計算して設定 41 // 基本速度100に、経過時間x10を加える 42 float speed = 100 + (_totalTime * 10); 43 blockScript.SetSpeed(-speed); // 左方向なのでマイナス 44 45 // ②生成回数をカウントアップ 46 _cnt++; 47 if (_cnt % 10 < 3) 48 { 49 // 0.1秒後にまた生成する 50 _timer += 0.1f; 51 } 52 else 53 { 54 // 1秒後にまた生成する 55 _timer += 1; 56 } 57 } 58 } 59}

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class BlockMgr2 : MonoBehaviour 6{ 7 // 生成するBlockオブジェクト 8 public GameObject block; 9 10 // 0になったらBlockオブジェクトを生成 11 float _timer = 0; 12 // トータルの経過時間を保持 13 float _totalTime = 0; 14 // ①ブロック生成回数 15 int _cnt = 0; 16 17 18 19 bool _isStart = false; 20 21 void Start() 22 { 23 Invoke("second", 3); 24 } 25 26 void second() 27 { 28 _isStart = true; 29 } 30 31 32 void Update() 33 { 34 if (!_isStart) 35 { 36 return; 37 } 38 // 経過時間を差し引く 39 _timer -= Time.deltaTime; 40 // トータル時間を加算 41 _totalTime += Time.deltaTime; 42 43 if (_timer < 0) 44 { 45 // 0になったのでBlock生成 46 // BlockMgrの場所から生成 47 Vector3 position = transform.position; 48 // ※上下(±3)のランダムな位置に出現させる 49 position.y = Random.Range(-3, 5); 50 // プレハブをもとにBlock生成 51 GameObject obj = Instantiate(block, position, Quaternion.identity); 52 // Blockオブジェクトの「Block」スクリプトを取得する 53 Block blockScript = obj.GetComponent<Block>(); 54 // 速度を計算して設定 55 // 基本速度100に、経過時間x10を加える 56 float speed = 100 + (_totalTime * 10); 57 blockScript.SetSpeed(-speed); // 左方向なのでマイナス 58 59 // ②生成回数をカウントアップ 60 _cnt++; 61 if (_cnt % 10 < 3) 62 { 63 // 0.1秒後にまた生成する 64 _timer += 0.1f; 65 } 66 else 67 { 68 // 1秒後にまた生成する 69 _timer += 1; 70 } 71 } 72 } 73} 74

c#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5// ブロック 6public class Block : MonoBehaviour 7{ 8 Rigidbody2D _rigidbody; 9 float _speed = -100; // 移動速度 10 11 void Start() 12 { 13 // 物理挙動コンポーネントを取得 14 _rigidbody = GetComponent<Rigidbody2D>(); 15 // 力を加える 16 _rigidbody.AddForce(new Vector2(_speed, 0)); 17 18 } 19 20 void Update() 21 { 22 Vector2 position = transform.position; 23 if (position.x < GetLeft()) 24 { 25 Destroy(gameObject); // 画面外に出たので消す. 26 } 27 } 28 29 float GetLeft() 30 { 31 // 画面の左下のワールド座標を取得する 32 Vector2 min = Camera.main.ViewportToWorldPoint(Vector2.zero); 33 return min.x; 34 } 35 36 public void SetSpeed(float speed) 37 { 38 _speed = speed; 39 } 40 41 42}

###追記(Block.cs)
Block.csのUpdate関数内のdestroyを削除したらエラーは起こりませんでした。

c#

1void Update() 2 { 3 Vector2 position = transform.position; 4 if (position.x < GetLeft()) 5 { 6 //Destroy(gameObject); // 画面外に出たので消す. 7 } 8 }

補足情報(FW/ツールのバージョンなど)

unity20203.1f1

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sakura_hana

2021/03/30 10:23

エラーメッセージを読みましょう。「Destroyされたオブジェクトにアクセスしようとしている」というエラーが「at Assets/Scripts/BlockMgr2.cs:51」、つまりBlockMgr2の51行目で起こっています。 その行を見るに「block」がどこかでDestroyしていそうです。対象のオブジェクトが最初からシーン上にありBlockクラスUpdate内Destroyで消えている可能性が高そうですがどうなっていますか? 他の理由で消えていたりしませんか?
unitykun

2021/03/31 03:41

追記に書かせていただきました。 ただ、重くなるとは思うので思うので、別の方法で画面外に出た場合のブロック削除方法を教えていただきたいです。
guest

回答1

0

ベストアンサー

Instantiateでの生成元となるオブジェクト(=block変数にセットされているオブジェクト)がDestroyされるのが問題です。
それ以外の、Instantiateで生成した後のオブジェクトはDestroyしても問題ありません。
「コピー元が存在しなければコピーはできない」「コピー後のオブジェクトを削除してもコピー元に影響は与えない」とイメージするとわかりやすいと思います。

ということは、「生成元だったらDestroyしない」「生成元をシーン上に配置しない」「そもそもDestroyしない」のいずれかで解決できます。

■生成元だったらDestroyしない
Destroy(gameObject);の前にif (gameObject.name != "生成元のオブジェクト名")という条件分岐を付け足すなどして、自身が生成元のオブジェクトである場合は削除されないようにしましょう。

■生成元をシーン上に配置しない
生成元のオブジェクトをProjectパネルにドラッグ&ドロップし、そのProjectパネル内のオブジェクトをBlockMgrクラスの変数にドラッグ&ドロップし、シーン上にある生成元オブジェクトは削除してください。
これで生成元オブジェクトはプレハブ化され、初期状態ではシーン上に存在しないのでUpdateも実行されず、Destroyすることもありません。(プレハブについての説明は割愛するので必要に応じて調べてください)

■そもそもDestroyしない
「ブロックが目的地に到着したら初期位置に移動する」「ブロックが既にある場合は新規生成しない」というコードに変更します。
考え方としては「オブジェクトプール」というものになります。こちらもググってみてください。

なお、いずれの場合もBlockMgr・BlockMgr2と複数の同内容のクラスを用意する必要性が現状見当たらないのでその点は再検討した方がよいかと思います。

投稿2021/04/02 00:23

sakura_hana

総合スコア11427

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

unitykun

2021/04/02 06:14 編集

回答ありがとうございます。 一つ目の案を参考させていただきました。 BlockMgr・BlockMgr2の件についてもアドバイスありがとうございます。すごく修正しやすいスクリプトに変えることができました。 ``` using System.Collections; using System.Collections.Generic; using UnityEngine; public class BlockMgr : MonoBehaviour { // 生成するBlockオブジェクト public GameObject block; // 0になったらBlockオブジェクトを生成 float _timer = 0; // トータルの経過時間を保持 float _totalTime = 0; // ①ブロック生成回数 int _cnt = 0; int mord = 1; void Start() { Invoke("normal", 3); Invoke("hard", 6); Invoke("difficult", 9); Invoke("impossible", 12); } void normal() { mord = 2; } void hard() { mord = 3; } void difficult() { mord = 4; } void impossible() { mord = 5; } void Update() { for (int i = 0; i < mord; i++) { // 経過時間を差し引く _timer -= Time.deltaTime; // トータル時間を加算 _totalTime += Time.deltaTime; if (_timer < 0) { // 0になったのでBlock生成 // BlockMgrの場所から生成 Vector3 position = transform.position; // ※上下(±3)のランダムな位置に出現させる position.y = Random.Range(-3, 5); // プレハブをもとにBlock生成 GameObject obj = Instantiate(block, position, Quaternion.identity); // Blockオブジェクトの「Block」スクリプトを取得する Block blockScript = obj.GetComponent<Block>(); // 速度を計算して設定 // 基本速度100に、経過時間x10を加える float speed = 100 + (_totalTime * 20); blockScript.SetSpeed(-speed); // 左方向なのでマイナス // ②生成回数をカウントアップ _cnt++; if (_cnt % 10 < 3) { // 0.1秒後にまた生成する _timer += 0.1f; } else { // 1秒後にまた生成する _timer += 1; } } } } } ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問