🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1382閲覧

unity for文の処理について

BRAK

総合スコア98

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/03/07 03:05

編集2021/03/07 12:45

マップ生成時のfor文の処理について

2Dゲームでマップ生成時に縦11横18の文字コード × 9 回を読み込んでfor文を回してマップを生成したのですが、ビルドしたら
マップが生成されなかったのですが、これは処理が間に合わなかったということでしょうか。

処理順を変えたら、プレイヤーが生成される時とされない時があったので、恐らく処理が間に合わなかったのだと思います。

また、読み終わるまで処理を続けたいのですが、どうすればよろしいでしょうか。

考えていることは、
・スクリプトを9個に分けて個々で処理をさせる
・描画するマップ位置のみ生成する(書いてきたコードがすべて破綻してしまうので厳しいです)
しか思いつきません

他に良い方法はないでしょうか。

ものすごい長いですが

定義(特に見る必要はなし)

C#

1コード 2 /// <summary> 3 /// イベントブロック説明をJsonから取得します 4 /// </summary> 5 JsonInfo ji; 6 7 /// <summary> 8 /// 生成する初期位置 9 /// </summary> 10 readonly Vector2 createInitPos = new Vector2(-8.5f, 5.5f); 11 12 #region 生成するオブジェクト 13 14 #region ステージごとに変わるタイル 15 16 //----------WALL----------// 17 [Header("Wall")] 18 /// <summary> 19 /// 壁 20 /// </summary> 21 [SerializeField] WallsClass[] wc; 22 23 //----------BackGround----------// 24 [Header("BackGround")] 25 /// <summary> 26 /// 背景 27 /// </summary> 28 [SerializeField] BackGroundClass[] bc; 29 30 //----------Decoration----------// 31 [Header("Decoration")] 32 /// <summary> 33 /// 装飾 34 /// </summary> 35 [SerializeField] DecorationClass[] dc; 36 37 #endregion 38 39 #region 全ステージ共通のタイル 40 41 //----------PLAYER ENEMY GOAL----------// 42 [Header("Player/Goal")] 43 /// <summary> 44 /// プレイヤー 45 /// </summary> 46 [SerializeField] GameObject player; 47 [SerializeField] GameObject goal; 48 [Header("Enemy")] 49 /// <summary> 50 /// エネミー 51 /// </summary> 52 [SerializeField] GameObject[] enemy; 53 54 //----------JUMP----------// 55 [Header("Jump")] 56 /// <summary> 57 /// 初期位置 58 /// </summary> 59 [SerializeField] GameObject initPos; 60 61 /// <summary> 62 /// ジャンプ台 63 /// </summary> 64 [SerializeField] GameObject[] jumpObj; 65 66 //----------EventItem----------// 67 [Header("EventItem")] 68 [SerializeField] GameObject[] item; 69 70 //----------EventBlock----------// 71 [Header("EventBlock")] 72 [SerializeField] GameObject[] block; 73 74 //----------EventBlock----------// 75 [Header("Move")] 76 [SerializeField] GameObject moveObj; 77 [SerializeField] GameObject[] catArrow; 78 79 #endregion 80 81 #endregion 82 83 /// <summary> 84 /// 各ステージフロア作成 85 /// </summary> 86 /// <param name="tileNum">タイルナンバー</param> 87 /// <param name="pos">生成位置</param> 88 /// <param name="floor">生成元の親オブジェクト</param> 89 /// <param name="floorNum">現在のフロア数</param> 90 delegate void TileMap(string tileNum, Vector2 pos, GameObject floor, int floorNum); 91 TileMap[] tileList; 92 TileMap tile; 93 readonly string[] pathName = { "Wall", "PlayerGoal", "Enemy", "Jump", "Move", "EventItem", "EventBlock", "BackGround", "Decoration" }; 94 /// <summary> 95 /// 生成カウント 96 /// </summary> 97 int counter = 0; 98 /// <summary> 99 /// 矢印用カウンタ― 100 /// </summary> 101 int arrowCounter = 0; 102 /// <summary> 103 /// ステージ番号 104 /// ステージ選択時にセットします 105 /// </summary> 106 static int fileNum = 0; 107 /// <summary> 108 /// ステージ内のフロア数 109 /// </summary> 110 readonly static int[] floorCount = { 3, 8 }; 111 /// <summary> 112 /// 現在のステージのフロア数を返します 113 /// </summary> 114 public static int FloorCount 115 { 116 get 117 { 118 return floorCount[fileNum]; 119 } 120 } 121 122 /// <summary> 123 /// 各ステージのX,Y長さ 124 /// </summary> 125 readonly Vector2[] stageVec = { new Vector2(19 - 1, 11 + 1), new Vector2(20 - 1, 11) }; 126 127 /// <summary> 128 /// 横のステージのフロア数 129 /// </summary> 130 readonly static int[] stageX = { 3, 4 }; 131 public static int StageX 132 { 133 get 134 { 135 return stageX[fileNum]; 136 } 137 } 138 139 /// <summary> 140 /// ステージ番号 141 /// </summary> 142 public static string stageID = ""; 143

Awake時、読み込む関数を格納

CreateStage()
フロアによって位置を変えて各フロアの位置を出します

C#

1コード 2 private void Awake() 3 { 4 //ステージ番号のステージを作成します 5 fileNum = GameManager.Instance.StageNo; 6 //fileNum = 0; 7 8 //現在のステージ番号を指定します 9 stageID = string.Format("stage{0}", fileNum + 1); 10 11 ji = new JsonInfo(); 12 ji.MapJson(); 13 14 tileList = new TileMap[] 15 { 16 SwicthWALL,//壁を生成 17 SwitchPlayerGoal,//プレイヤーとゴールを生成 18 SwitchEnemy,//敵を生成 19 SwitchJump,//ジャンプ台を生成 20 SwitchMove,//フロア移動 21 SwitchEventItem,//イベントアイテムを生成 22 SwitchEventBlock,//イベントブロックを生成 23 SwitchBack,//背景生成 24 SwitchDecoration//デコレーション生成 25 }; 26 27 //ステージ作成 28 CreateStage(); 29 30 //オブジェクトを破棄します 31 //Destroy(gameObject); 32 } 33 34 #region マップ生成読み込み 35 36 /// <summary> 37 /// ステージの作成 38 /// </summary> 39 void CreateStage() 40 { 41 //CSVからデータを読み込む 42 for (int sNum = 0; sNum < FloorCount; sNum++) 43 { 44 //余りが横 45 float stageVecX = sNum % StageX; 46 //商が縦 47 float stageVecY = sNum / StageX; 48 49 var vec = Vector2.zero; 50 //このステージの横縦長さ * ステージのx(横のフロア)とy(縦のフロア)の何番目か + 作成する初期位置 51 vec.x = stageVec[fileNum].x * stageVecX + createInitPos.x; 52 vec.y = (-stageVec[fileNum].y) * stageVecY + createInitPos.y; 53 54 55 //ステージを格納する空のオブジェクトを作成(フロアごとに分けてここに入れます) 56 var obj = Resources.Load<GameObject>("StageEmpty"); 57 var floor = Instantiate(obj, transform.position, Quaternion.identity); 58 floor.name = sNum.ToString(); 59 60 for (int i = 0; i < tileList.Length; i++) 61 { 62 var stageNo = fileNum + 1; 63 var filePath = string.Format("Stage/Stage{0}/{1}/{2}", stageNo, sNum + 1, pathName[i]); 64 CSVRead(filePath, i, floor, vec, sNum); 65 } 66 } 67 }

CSVRead() CSVからの読み込み(JSON)

C#

1コード 2 /// <summary> 3 /// CSVファイルの読み込み 4 /// </summary> 5 void CSVRead(string stageTagName, int num, GameObject floor, Vector2 createPos, int floorNum) 6 { 7 //csvファイルの検索 8 var csvFile = Resources.Load(stageTagName) as TextAsset; 9 10 if (csvFile == null) return; 11 12 //csvファイルの読み込み 13 var reader = new StringReader(csvFile.text); 14 15 //数字文字を解析しステージを作成します 16 StringMozi(reader, num, floor, createPos, floorNum); 17 }

StringMozi() CSVの文字 (例え)横11行縦18列の読み込み

C#

1コード 2 /// <summary> 3 /// ファイルの内の","で文字を区切ります 4 /// </summary> 5 void StringMozi(StringReader reader, int num, GameObject floor, Vector2 createPos, int floorNum) 6 { 7 var pos = createPos; 8 tile = tileList[num]; 9 //読み取り対象がなくなるまで繰り返します 10 while (reader.Peek() != -1) 11 { 12 //一行づつ読み込みます 13 string line = reader.ReadLine(); 14 15 string[] split = line.Split(',');//,で区切ります 16 foreach (var tileNum in split) 17 { 18 //現在の作成物 19 tile(tileNum, pos, floor, floorNum); 20 //生成位置を変更します 21 pos.x += 1; 22 } 23 //xを初期位置yを-1下げたところから生成を再開しします 24 pos.x = createPos.x; 25 pos.y -= 1; 26 } 27 //生成カウントの初期化 28 counter = 0; 29 arrowCounter = 0; 30 }

もしかしたら、JSONのデータから値を割り当てる際にUnity上では正常に動いていたけど、ビルドすると壊れることが起こっているのかもしれません。

フロア生成順の際にJsonから参照するブロックを生成したときにブロックのみ生成されてそこでfor文が死んだような現象が起こったので、わからないですが。。

      SwicthWALL,//壁を生成
SwitchPlayerGoal,//プレイヤーとゴールを生成
SwitchEnemy,//敵を生成
SwitchJump,//ジャンプ台を生成
SwitchMove,//フロア移動

この順番だと、Moveまで生成されます。しかし、EnemyやMoveもJsonを参照しているので訳が分かりません。

イメージ説明

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

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

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

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

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

fiveHundred

2021/03/07 03:32

Unityでは基本的な処理はシングルスレッドなので、処理が間に合わない場合は他の基本的な処理も行われないため、フリーズや処理落ちという形になる気がします。 あくまで私の意見で違うかもしれませんが、メモリ不足が原因なのではないかと推測します。 いずれにせよ、現状では情報が少なくて状況がつかめないので、せめてコードぐらいは提示してくれると回答しやすくなると思います。
BRAK

2021/03/07 03:34 編集

回答ありがとうございます。 帰宅したらコード載せます。 よろしくお願いします。
fiveHundred

2021/03/07 12:12

tileListに格納されている「Swicth~」という関数はどうなっていますか?
BRAK

2021/03/07 12:14

そこは、CSVから読み込んだ文字がたとえば1だったら草むらのタイルを置くという処理になっています。 swicth文で場合分けしています。 それをそれぞれで行っています。 prefabsの配列からタイルを取り出す形です。
BRAK

2021/03/07 12:16 編集

```C# コード void SwicthWALL(string tileNum, Vector2 pos, GameObject floor, int floorNum) { //ステージごとの壁を生成します string[][] wallNo = new string[2][] { new string[]{ "22", "23", "24", "28", "29", "278", "279", "280", "284", "285", "534", "535", "536"}, new string[]{"6","7","8","9","262","263","264","265","518","519","520","521","770", "1031","1032","1033","1034","1286","1287","1288","1289","1542","1543","1544","1545"} }; //読み込んだ文字数値がwallNo配列にあるかを解析し、配列番号のオブジェクトを //現在のフロアに生成します。 if (!OnMozi(wallNo[fileNum], tileNum, 0)) { //wc[ステージ番号][wallNoの番号]のオブジェクトを生成 InstantObj(wc[fileNum].walls[SetNumber(wallNo[fileNum], tileNum)], pos, floor); } } ```
BRAK

2021/03/07 12:21

また、Jsonのデータを参照するオブジェクトもあります。
BRAK

2021/03/07 12:32

//JSON内で定義した連想配列を割り当てるためのクラス ```C# コード [System.Serializable] //ブロックの説明 public class Block:ID { public BlockFloor[] floor; } /// <summary> /// フロア内のブロック /// </summary> [System.Serializable] public class BlockFloor { public string[] name; /// <summary> /// 次の面に移動するフラグを持つブロック /// MeatObjとCatArrowを表示させる /// </summary> public string[] jumpFloor; /// <summary> /// イベントブロック /// </summary> public string[] ev; /// <summary> /// ゴールブロック /// </summary> public string[] goal; public string GetName(string type, int num) { string ret = null; switch (type) { case "ev": ret = ev[num]; break; case "goal": ret = goal[num]; break; } return ret; } } ``` //Jsonから値を参照するクラスが継承するIDクラス //GetDataNo()ここ参照しデータを割り当てていきます // ---> もしかしてジェネリック型がよくないとかありますか? ```C# コード /// <summary> /// 全てのJsonが持つStageID /// </summary> [System.Serializable] public class ID { public string id; /// <summary> /// StageIdから指定のJsonListに格納された要素を見つけます /// </summary> /// <typeparam name="T">IDクラスを継承しているJsonのクラスT</typeparam> /// <param name="dataId">現在のstage番号</param> /// <param name="data">Jsonクラス</param> public static T GetDataNo<T>(List<T> data, string dataId) where T : ID { //ステージIDのリスト配列番号を取得 var dataNo = data.Find(dt => dt.id == dataId); if (dataNo == null) { Debug.LogError("sceneId:名前が違う,id名が配列外エラー"); Debug.LogError("scenarioName:名前が違う,Resourcesの中にあるJsonファイルを参照"); } //そのステージ名が何番目にあるかを取得 var index = data.IndexOf(dataNo); return data[index]; } } ``` //Jsonブロッククラス ```C# コード //クラスに格納 [System.Serializable] public class BlockList { public List<Block> blocks = new List<Block>(); } ``` //Switch~でオブジェクトを生成する時に参照する関数(たとえばブロッククラス) //Jsonデータからの割り当て ```C# コード //Jsonで定義したクラス ブロックリスト public BlockList blockList; /// <summary> /// 指定のブロックに値を代入 /// </summary> /// <param name="stageId">ステージ名</param> /// <param name="blockName">ブロック名(ev,goal)</param> /// <param name="num">生成カウント(何番目か)</param> /// <param name="block"></param> /// <param name="floorNum">現在のフロア数</param> public void SetBlock(string stageId, string blockName, BlocksScript block, int num, int floorNum) { //ブロッククラスを定義 var b = ID.GetDataNo(blockList.blocks, stageId).floor[floorNum]; //ブロックの説明を取得 var des = b.GetName(blockName, num); //移動はあるか var f = b.jumpFloor[num]; //名前 var name = b.name[num]; //値の代入 block.SetBlock(des, name, f); } ```
BRAK

2021/03/07 12:36 編集

ADVパートも作成しており、その出力の時にもここのJSONの関数を使っています。 その際にもJSONからシナリオを読みだせなかったので、もしかしたらビルドしたときにおかしくなっているということもあるかもしれません。(----> Unity上では動きます)
fiveHundred

2021/03/07 23:56

その様子だと、私はちょっと分からないですね。すいません。 「ブロックを生成しようとする度に、Resources.Loadでプレハブを毎回ロードしている」ということがあるかもしれないと思っていたのですが、見た感じそうでもなさそうですし。
退会済みユーザー

退会済みユーザー

2021/03/08 02:30

jsonデータの読み込みが出来ているかの確認が必要ですね。 なんとなくですが、script execution orderが関係あるかも?とも思いました
BRAK

2021/03/08 03:49

five Hundredさんありがとうございます。
BRAK

2021/03/08 03:51

ビルド上でのJSONデータの読み込みが部分的に欠落しているという感じですかね。 確認してみます。
BRAK

2021/03/08 03:55

script execution orderについて今調べましたが、スクリプトの実行順序は変えました。 もしかしてここが問題という可能性がありますか。
退会済みユーザー

退会済みユーザー

2021/03/08 06:57

処理順を変えたら、とありましたのでjsonデータから生成されて初期化される前にそのデータを使用するメソッドが走ってしまっている可能性があるのかな?と思ったのです。これがエディタとビルドで変わるか?は不明です。 なのでJsonのデータが確実に読まれているか?を確認するのがまず先だと思います。 これに関しては読み込み関係をAwake、後の処理をStartに変更でも確認できます。すべてAwakeとかだと可能性の一つとしてあるかなぁ?と。Awake中に別のオブジェクトを初期化して使うみたいな事をするとnullったりした記憶がありますので。 少なくともfor文自体の問題ではなく、その中の処理の問題のはずです。
BRAK

2021/03/08 07:08

Jsonの読み込みはAwakeで処理しており。ほかはStartで分けて処理はしております。 これでエディタ上で確実に動いているので問題はないと思うのですが、、一度確認してみます。
guest

回答1

0

自己解決

Resourcesのファイル読み込みを下記で指定してあげると読み込みます。
Resources.Load<TextAsset>(stageTagName).text;

投稿2023/02/08 03:54

BRAK

総合スコア98

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問