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

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

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

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

Unity

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

Q&A

解決済

1回答

1464閲覧

Unityで3色(色固定・重複無し)のターゲットを3つランダムに等間隔で配置することを目的にC#スクリプトを作成していますが,色の重複が起きてしまいます.

toririn_blue

総合スコア2

C#

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

Unity

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

0グッド

0クリップ

投稿2021/09/29 16:12

編集2021/09/30 07:37

前提・実現したいこと

初めての質問投稿になります.
私はUnityを独学で勉強している最中のため,用語の使い方など不正確な点もあると思いますが,よろしくお願いします.

環境としては,Mac BookAir(M1)で,unityのバージョンは2020.3.0f1です.

Unityで3色(色固定・重複無し)のターゲットを3つ,ランダムに等間隔で配置することを目的にスクリプトを作成しています.

スクリプトの内容としては,

0.ターゲットをprefab化しておく.(前提)
1.そのprefabをインスタンス化してオブジェクトを生成する.
2.生成したオブジェクトを等間隔に配置する.
3.prefabのマテリアルを変えることで,色を変える.

と考えています.

####理想的な実行結果
![理想的な実行結果]
偶然成功したもの

####現在の実行結果
現在の実行結果

該当のソースコード

prefabを生成し配置するソースコードは,こちらのサイトを参考にしています.
https://ekulabo.com/prefab-block-sample

重複無しで数字を出力するソースコードは,こちらのサイトを参考にしています.
https://tech.pjin.jp/blog/2018/02/01/unity_random-number_nonoverlap/

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5/// <Summary> 6/// Prefabのオブジェクトを並べるサンプルスクリプトです。 7/// </Summary> 8public class PrefabPlaceSample : MonoBehaviour 9{ 10 // オブジェクトを生成する元となるPrefabへの参照を保持します。 11 public GameObject prefabObj; 12 13 // 生成したオブジェクトの親オブジェクトへの参照を保持します。 14 public Transform parentTran; 15 16 // マテリアルを保持します。 17 public Material redMat; 18 public Material yellowMat; 19 public Material whiteMat; 20 21void Start() 22 { 23 CreateBlockObject(); 24 } 25 26 /// <Summary> 27 /// Prefabからブロックとして使うオブジェクトを生成します。 28 /// </Summary> 29 void CreateBlockObject() 30 { 31 int row = 1; 32 int column = 3; 33 float xOffset = 2.5f; 34 float zOffset = 7.1f; 35 36 List<int> numbers = new List<int>(); 37 38 for (int j = 0; j < row; j++) 39 { 40 for (int i = 0; i < column; i++) 41 { 42 // ゲームオブジェクトを生成します。 43 GameObject obj = Instantiate(prefabObj, Vector3.zero, Quaternion.identity); 44 45 // ゲームオブジェクトの親オブジェクトを設定します。 46 obj.transform.SetParent(parentTran); 47 48 // ゲームオブジェクトの位置を設定します。 49 float xPos = xOffset * i; 50 float zPos = zOffset * j; 51 obj.transform.localPosition = new Vector3(xPos, 0.0f, zPos); 52 53 // マテリアルをランダムで設定します。 54 for (int k = row; k <= column; k++) 55 { 56 // まず,List numbers に数字を追加します. 57 numbers.Add(k); 58 } 59 while (numbers.Count > 0) 60 { 61 // ランダムに数字を取り出します. 62 int index = Random.Range(0, numbers.Count); 63 int ransu = numbers[index]; 64 Material mat = whiteMat; 65 // 乱数の結果により,マテリアルを変更します. 66 switch (ransu) 67 { 68 case 1: 69 mat = redMat; 70 break; 71 case 2: 72 mat = yellowMat; 73 break; 74 } 75 //重複を避けるため,利用した数字をnumbersから消します. 76 numbers.RemoveAt(index); 77 obj.GetComponent<MeshRenderer>().material = mat; 78 79 } 80 } 81 } 82 } 83}

試したこと

forでループする際に,数字のlistであるnumbersに要素を追加しているのではと考え,ループする前(最初のforの前)に

for (int k = row; k <= column; k++) { // まず,List numbers に数字を追加します. numbers.Add(k); }

追加してみましたが,一番最初のターゲット以外はマテリアルが変更されませんでした.

###修正1
1570pさんに,case 0 (case 3)(つまりmaterialをransuを使って変更しない)場合に何か起きているのでは?とご指摘していただいたので,defaultMatというmaterialから必ずransuを用いて,materialを変更するように,下記のように書き換えました.

実行結果としては,変わりませんでした.

修正したコード1

public class PrefabPlaceSample : MonoBehaviour { // オブジェクトを生成する元となるPrefabへの参照を保持します。 public GameObject prefabObj; // 生成したオブジェクトの親オブジェクトへの参照を保持します。 public Transform parentTran; // マテリアルを保持します。 public Material redMat; public Material yellowMat; public Material whiteMat; public Material defaultMat; 〜〜〜 while (numbers.Count > 0) { // ランダムに数字を取り出します. int index = Random.Range(0, numbers.Count); int ransu = numbers[index]; Material mat = defaultMat; // 乱数の結果により,マテリアルを変更します.(修正済み) switch (ransu) { case 1: mat = redMat; break; case 2: mat = yellowMat; break; case 3: mat = whiteMat; break; } //重複を避けるため,利用した数字をnumbersから消します. numbers.RemoveAt(index); obj.GetComponent<MeshRenderer>().material = mat; } 〜〜〜

最後に

ここまで読んでいただきありがとうございます.
回答する上で,足りない情報等ございましたら,お知らせください.
ご指導のほどよろしくお願いいたします.

解決記録

Bongoさんのご指摘の通り,書き換えたところ目的通りのスクリプトが完成しました.

完成したコード

using System.Collections; using System.Collections.Generic; using UnityEngine; /// <Summary> /// Prefabのオブジェクトを並べるサンプルスクリプトです。 /// </Summary> public class PrefabPlaceSample : MonoBehaviour { // オブジェクトを生成する元となるPrefabへの参照を保持します。 public GameObject prefabObj; // 生成したオブジェクトの親オブジェクトへの参照を保持します。 public Transform parentTran; // マテリアルを保持します。 public Material redMat; public Material yellowMat; public Material whiteMat; public Material defaultMat; void Start() { CreateBlockObject(); } /// <Summary> /// Prefabからブロックとして使うオブジェクトを生成します。 /// </Summary> void CreateBlockObject() { int row = 6; int column = 3; float xOffset = 2.5f; float zOffset = 7.1f; List<int> numbers = new List<int>(); for (int j = 0; j < row; j++) { numbers.Clear(); for (int k = 1; k <= column; k++) { // まず,List numbers に数字を追加します. numbers.Add(k); } for (int i = 0; i < column; i++) { // ゲームオブジェクトを生成します。 GameObject obj = Instantiate(prefabObj, Vector3.zero, Quaternion.identity); // ゲームオブジェクトの親オブジェクトを設定します。 obj.transform.SetParent(parentTran); // ゲームオブジェクトの位置を設定します。 float xPos = xOffset * i; float zPos = zOffset * j; obj.transform.localPosition = new Vector3(xPos, 0.0f, zPos); // マテリアルをランダムで設定します。 if (numbers.Count > 0) { // ランダムに数字を取り出します. int index = Random.Range(0, numbers.Count); int ransu = numbers[index]; Material mat = defaultMat; // 乱数の結果により,マテリアルを変更します.(修正済み) switch (ransu) { case 1: mat = redMat; break; case 2: mat = yellowMat; break; case 3: mat = whiteMat; break; } //重複を避けるため,利用した数字をnumbersから消します. numbers.RemoveAt(index); obj.GetComponent<MeshRenderer>().material = mat; } } } } }

実行結果

行内で,3色(色固定・重複無し)のターゲットを3つランダムに等間隔で配置できています.
(画像は3列の場合)
完成したスクリプトの実行結果

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/09/30 03:23

なんとなくですが、case 0:の時におかしくなりそう?
toririn_blue

2021/09/30 06:46

ご指摘ありがとうございます. case 0 (case 3)(つまりmaterialをransuを使って変更しない)場合に,whileのループで何か起きている可能性はがあると思われましたので,修正してみましたが,実行結果は変わりませんでした. 詳細は質問の方に追記してありますので,確認いただけると幸いです.
Bongo

2021/09/30 06:57

私の提示しましたコードにはもう一つ「whileをifに変える」という変更を加えてあるのですが(本文中では言及しませんでしたのでお見逃しかもしれません...すみませんでした)、それを行うとどうなりますでしょうか?
toririn_blue

2021/09/30 07:40

whileをifに書き換えるところを一度見落とした状態で,修正をしてしまいました.whileをifに書き換えたところ,目的通りのスクリプトが完成しました.詳細は解決記録として,質問に追記しておきましたので,ご確認のほど,よろしくお願いいたします.
guest

回答1

0

ベストアンサー

「forでループする際に,数字のlistであるnumbersに要素を追加しているのでは」という点にご注目なさっているのは的確かと思います。
下記の位置で要素追加を行ってみてはいかがでしょうか?

lang

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5/// <Summary> 6/// Prefabのオブジェクトを並べるサンプルスクリプトです。 7/// </Summary> 8public class PrefabPlaceSample : MonoBehaviour 9{ 10 // オブジェクトを生成する元となるPrefabへの参照を保持します。 11 public GameObject prefabObj; 12 13 // 生成したオブジェクトの親オブジェクトへの参照を保持します。 14 public Transform parentTran; 15 16 // マテリアルを保持します。 17 public Material redMat; 18 public Material yellowMat; 19 public Material whiteMat; 20 21 void Start() 22 { 23 CreateBlockObject(); 24 } 25 26 /// <Summary> 27 /// Prefabからブロックとして使うオブジェクトを生成します。 28 /// </Summary> 29 void CreateBlockObject() 30 { 31 int row = 1; 32 int column = 3; 33 float xOffset = 2.5f; 34 float zOffset = 7.1f; 35 36 List<int> numbers = new List<int>(); 37 38 for (int j = 0; j < row; j++) 39 { 40 // このタイミングでnumbersを初期状態にしてはいかがでしょう 41 // ※マテリアルの種類はcolumnと同数であることが暗黙の前提で、各列にそれぞれバラバラなマテリアルを 42 // 割り当てるのだろうと勝手に解釈したのですが、もしそうであればnumbersに追加する値は下記のように 43 // 1~columnになるんじゃないでしょうかね? 44 numbers.Clear(); 45 for (int k = 1; k <= column; k++) 46 { 47 // まず,List numbers に数字を追加します. 48 numbers.Add(k); 49 } 50 51 for (int i = 0; i < column; i++) 52 { 53 // ゲームオブジェクトを生成します。 54 GameObject obj = Instantiate(prefabObj, Vector3.zero, Quaternion.identity); 55 56 // ゲームオブジェクトの親オブジェクトを設定します。 57 obj.transform.SetParent(parentTran); 58 59 // ゲームオブジェクトの位置を設定します。 60 float xPos = xOffset * i; 61 float zPos = zOffset * j; 62 obj.transform.localPosition = new Vector3(xPos, 0.0f, zPos); 63 64 // マテリアルをランダムで設定します。 65 // whileだと、numbersから値を全部取り出し尽くすまでマテリアル設定処理が 66 // 行われてしまうでしょうから、ifに変更しました 67 if (numbers.Count > 0) 68 { 69 // ランダムに数字を取り出します. 70 int index = Random.Range(0, numbers.Count); 71 int ransu = numbers[index]; 72 Material mat = whiteMat; 73 // 乱数の結果により,マテリアルを変更します. 74 switch (ransu) 75 { 76 case 1: 77 mat = redMat; 78 break; 79 case 2: 80 mat = yellowMat; 81 break; 82 } 83 //重複を避けるため,利用した数字をnumbersから消します. 84 numbers.RemoveAt(index); 85 obj.GetComponent<MeshRenderer>().material = mat; 86 } 87 } 88 } 89 } 90}

投稿2021/09/29 19:37

Bongo

総合スコア10811

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

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

toririn_blue

2021/09/30 06:55

回答ありがとうございます. // ※マテリアルの種類はcolumnと同数であることが暗黙の前提で、各列にそれぞれバラバラなマテリアルを // 割り当てるのだろうと勝手に解釈したのですが、もしそうであればnumbersに追加する値は下記のように // 1~columnになるんじゃないでしょうかね? ご指摘の通りです.意図を汲み取っていただき助かりました. 提案していただいた通りに,コードを書き換えたところ,無事に解決できました! ご協力ありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問