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

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

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

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

Unity

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

Q&A

解決済

2回答

5668閲覧

配列をランダムに置き換えたい

YukioMaki

総合スコア21

C#

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

Unity

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

0グッド

0クリップ

投稿2017/12/17 01:25

...
using UnityEngine;
using System.Collections;

public class Stage : MonoBehaviour {

public Material[] material; private string[] layer = { "word1","word2","word3","word4","word5","word6","word7","word8","word9", "word10"};




void Word()
{
wd = Instantiate(WordPrefab, new Vector3(0, 1, 1), Quaternion.identity) as GameObject;
string layer = "word" + 1.ToString();
wd.gameObject.layer = LayerMask.NameToLayer(layer);
Renderer rend = wd.GetComponentInChildren<Renderer>();
rend.material = material[i];
i += 1;
}
・・・

マウスを押すごとにlayerの配列に入れたテキスチャーを表示するようにして実行出来たのですが、配列のまま表示しては面白くないのでアトランダムに表示したいと思います。
初心者でどう書いていいのか分からず詳しく教えていただけませんか。

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

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

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

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

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

guest

回答2

0

乱数を生成する

Google というサイトは便利なのでブックマークしておいてください。
ここにアクセスするとテキストボックス(文字の書けるところ)が出てきますので、そこに「C# 乱数」と書いてボタンを押すとたくさんのページへのリンクが表示されます。

投稿2017/12/17 01:36

Zuishin

総合スコア28660

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

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

YukioMaki

2017/12/17 01:58

Zuishinさん回答ありがとうございます。 でも、ここへ投稿する前にGoogleでしらべて、 ・・・ public static List<T> Shuffle<T>(this List<T> list){ for (int i = 0; i < list.Count; i++) { T temp = list[i]; int randomIndex = Random.Range(0, list.Count); list[i] = list[randomIndex]; list[randomIndex] = temp; } return list; } ・・・ このスクリプトをコピーしてそれを改善してみたのですがエラー、エラーで、 うまくコンパイラー出来るように教えてもらえますか。
Zuishin

2017/12/17 03:54

C# List シャッフル
Zuishin

2017/12/17 03:58

エラーになるともうそこで思考停止する人がいますが、エラーメッセージはどうしたらうまくいくか教えてくれるメッセージです。 エラーメッセージを読みましょう。 エラーメッセージを読みましょう。 エラーメッセージを読みましょう。 重要なことなので三回言いました。 それでもわからない場合はエラーメッセージを添えて聞きましょう。 それでもわからない場合はエラーメッセージを添えて聞きましょう。 それでもわからない場合はエラーメッセージを添えて聞きましょう。 あと、質問するときにプレビュー画面にインデントの消えた汚いソースが表示されたはずです。 気になりませんか? 読みやすくインデントをつけてください。
YukioMaki

2017/12/17 13:08

「エラーになるともうそこで思考停止する人がいます」そう私はそのタイプです。 だから、ここに投稿しました。 Zuishinさんに聞いても無駄のようですので、他の方で丁寧に教えていただける方いませんか。
Zuishin

2017/12/17 15:19 編集

すでに丁寧に教えました。 もう一度書きましょう。 C# List シャッフル
Zuishin

2017/12/17 15:19

もう一度書きましょう。 C# List シャッフル
YukioMaki

2017/12/17 16:26

あなたには尋ねていませんよ、Zuishinsan.
Zuishin

2017/12/17 16:35 編集

もう一度書きましょう。 C# List シャッフル。
guest

0

ベストアンサー

以下のページが参考になるので、一度読んでみてください。
参考ページ1
参考ページ2


2017/12/18 20:50 コメントを受けて追記

ソースコードはほぼ合っています。
一部 } の数などがおかしいので、動くように直すとこう。

C#

1private string[] layer = {"word1","word2","word3","word4","word5","word6","word7","word8","word9", "word10"}; 2 3for (int j = 0; j < layer.Length; j++) 4{ 5 string temp = layer[j]; //stringで問題無いです。 6 int randomIndex = Random.Range(0, layer.Length); 7 layer[j] = layer[randomIndex]; 8 layer[randomIndex] = temp; 9}

「かと言ってintをstringにかえても??」
何故疑問に思ったか分かりませんが、まさにそれが答えです。

Random.Rangeは検索すると分かりますが「第一引数から'第二引数-1'の内、ランダムな数1つを返す」というメソッドです。
layer.Lengthは10なので、Random.Range(0, layer.Length)は「0から9までのランダムな数字1つ」と同じ意味です。
これ自体はただのintを返すだけで、「Random.Rangeが配列の要素そのものを指すわけではない」ことに注意です。

これを踏まえてfor文の挙動を見てみましょう。

j = 0の時 tempにlayer[0]格納(temp = "word1") randomIndexにランダムな数字が入る(randomIndex = 3とする) layer[0]にlayer[3]が入る(layer[0] = "word4", layer[3] = "word4") layer[3]にtempが入る(layer[0] = "word4", layer[3] = "word1") 現在のlayer:0番目と3番目が入れ替わった {"word4","word2","word3","word1","word5","word6","word7","word8","word9", "word10"} j = 1の時 tempにlayer[1]格納(temp = "word2") randomIndexにランダムな数字が入る(randomIndex = 2とする) layer[1]にlayer[2]が入る(layer[1] = "word3", layer[2] = "word3") layer[2]にtempが入る(layer[1] = "word3", layer[2] = "word2") 現在のlayer:1番目と2番目が入れ替わった {"word4","word3","word2","word1","word5","word6","word7","word8","word9", "word10"} (以下、j=9まで続く)

というように、シャッフルが行われます。
挙動がおかしい場合は、「エラーコードを見て問題点を探す」「初めて見るメソッドはまず検索してみる」「プログラムや実際の挙動を日本語で書いてみる」等すると自力解決しやすいです。

なお、この方法だと低確率で「シャッフルされない」「1項目だけしかシャッフルされない」などのケースが出ます。

  • 全てのループでrandomIndexがjと同値になった場合(同じ場所のものを入れ替えるので並び替えされない)
  • シャッフル後に元に戻った場合(「j=0の時randomIndex=1、j=1の時randomIndex=0」などが続いた時) など

「絶対シャッフルされたい」「なるべくバラバラにシャッフルされたい」という場合は別の方法を調べてみてください。


2017/12/21 20:50 コメントを受けて追記

「layerの配列をシャッフルしたい」という質問だったのでそう答えましたが、
そもそもの話をすると、質問文のコードはlayer配列を使用していません。

void Word() の中で
string layer = "word" + 1.ToString();
と記載しているので、layer変数には常に"word1"が入っています。
更に言うとこのlayerはレイヤーマスクを指定しているだけであり、テクスチャの変更はしていないです。

順番に表示されているのは「マテリアルの配列(material変数)」です。
これで表示が切り替わるということは、material配列にテクスチャ違いのマテリアルが複数入っているということですね。

もう面倒臭いので「恐らくこういうことがしたいのだろう」という全コード書きますね。

C#

1//配列をシャッフルしてから順番に使用するパターン 2using UnityEngine; 3using System.Collections; 4 5public class Stage : MonoBehaviour { 6 7public Material[] material; 8private string[] layer = 9{ "word1","word2","word3","word4","word5","word6","word7","word8","word9", "word10"}; //定義していますが使っていません 10private int i; 11 12void Start() { 13 Shuffle (); //最初に配列シャッフルする 14} 15 16//配列をシャッフルするコード 17void Shuffle () { 18 for (int j = 0; j < material.Length; j++) 19 { 20 Material temp = material[j]; 21 int randomIndex = Random.Range(0, material.Length); 22 material[j] = material[randomIndex]; 23 material[randomIndex] = temp; 24 } 25} 26 27//シャッフルされた配列を使う 28void Word() 29{ 30 GameObject wd = Instantiate(WordPrefab, new Vector3(0, 1, 1), Quaternion.identity) as GameObject; 31 string layer = "word1"; 32 wd.gameObject.layer = LayerMask.NameToLayer(layer); 33 Renderer rend = wd.GetComponentInChildren<Renderer>(); 34 rend.material = material[i]; 35 i += 1; 36 37 //materialの数以上になるとエラーになるので、その場合0に戻す 38 if (i >= material.Length) { 39 i = 0; 40 } 41}

C#

1//別解:毎回ランダムで取得するパターン(かつ要らない変数をごっそり削除) 2using UnityEngine; 3using System.Collections; 4 5public class Stage : MonoBehaviour { 6 7public Material[] material; 8 9void Word() 10{ 11 GameObject wd = Instantiate(WordPrefab, new Vector3(0, 1, 1), Quaternion.identity) as GameObject; 12 wd.gameObject.layer = LayerMask.NameToLayer("word1"); 13 Renderer rend = wd.GetComponentInChildren<Renderer>(); 14 rend.material = material[Random.Range(0, material.Length)]; 15}

投稿2017/12/18 05:14

編集2017/12/21 11:47
sakura_hana

総合スコア11427

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

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

YukioMaki

2017/12/18 09:36

Sakura_hanaさん回答ありがとうございます。 参考ページ2を開いて私なりに下記のスクリプト書き換えて追加してみました。 ・・・ private string[] layer = { "word1","word2","word3","word4","word5","word6","word7","word8","word9", "word10"}; for (int j = 0; j < layer.Length; j++) { int temp = layer[j]; int randomIndex = Random.Range(0, layer.Length); layer[j] = layer[randomIndex]; layer[randomIndex] = temp;     } } ・・・ stringをintの中にほり込むのは無理なことは私にも分かるのですが、かと言ってintをstringにかえても?? Random自体0~配列の数までチョイスする、intで書かれているし、stringの配列をランダムするのは無理なのでしょうか?
sakura_hana

2017/12/18 11:23

前提条件の確認なのですが、目的としているのは「配列をランダムに並び替え(シャッフル)」ですか? それとも「配列の中からランダムに1つ抜き取り」ですか?
YukioMaki

2017/12/18 11:29

Sakura_hanaさんお手数かけてすいません。 「配列をランダムに並び替え」です。 最初にすべての配列を並び替えたいんです。
sakura_hana

2017/12/18 11:57

回答に追記しました。
sakura_hana

2017/12/18 12:01

ちなみに今回はがっつり回答しましたが 「teratailはサポートセンターではなく、思考するエンジニアの為のQ&Aコミュニティです」。 思考停止でも質問すれば回答貰えるだろ、という姿勢は閲覧者が悲しくなるので 次回以降は参考ページ1に則った質問の程、宜しくお願い致します。
YukioMaki

2017/12/19 02:03

sukura_hanaさん詳しい解説ありがとうございます。 ランダムが少しは理解できたと思います。 返事が遅くなったのはコンパイラーは通ったのですが、表示に変化がないので、スクリプトに Debug.Log(layer[j]);を付け加え動きを確かめようとしたのですが、Array index is out of range. SoundSystem.Awake () (at Assets/Script/SoundSystem.cs:9)の!がでているためにDebug.Log(layer[j])が表示されていません。 配列はAudioSource[] audio = GetComponents<AudioSource>();で オブジェクトをデストロイする時に1度音を鳴らすのに使っていいますが 範囲を超えているとは思えないのですが、色々スクリプトを書き換えている最中です。 !が消え、ランダムが構想どうりに作動出来るようになったらまたコメントします。 取り急ぎお礼申し上げます。
YukioMaki

2017/12/21 11:08

Debugを調べたところアトランダムになっていましたが、sakura_hanaさんがご指摘どうり、「Random.Rangeが配列の要素そのものを指すわけではない」と言うことで表示はリストの1~順番どうりで変わりませんでした。そこで方針を変えて、表示するテキスチャーだけをランダムに抽選し表示後そのテキスチャーをnullにしました。 nullにしたテキスチャーは表示しないために、if文で抽選したテキスチャーがnullだったと時はRundomに戻るようにしたところ構想どうりに動きました。 ・・・ void Word() { i = Random.Range(0, 9); if (material[i] == null) { Invoke("Word", 0); } d = 5; wd = Instantiate(WordPrefab, new Vector3(0, 1, 1), Quaternion.identity) as GameObject; string layer = "word" + i.ToString(); wd.gameObject.layer = LayerMask.NameToLayer("layer"); Renderer rend = wd.GetComponent<Renderer>(); rend.material = material[i]; material[i] = null; i += 1; Invoke("Deth", d); if (wd == true) { } } ・・・ 最初の方針、配列を置き換えて表示することも捨てがたく何か方法があればヒントを頂ければ嬉しいです。
sakura_hana

2017/12/21 11:47

回答に追記しました。
YukioMaki

2017/12/22 10:24

私が深場にはまったのは、レイヤーを並び換えれればテキスチャーも換えれると思っていた所にあるようですね。 方針を変えたコードは問題なく動くようでしたので、生徒の算数指導に今日使いました。 sakura_hanaさんの書いてくださったコードはこれからの生徒指導に役立つので、ゆっくり研究させて頂きます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問