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

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

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

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

Unity

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

Q&A

解決済

1回答

1720閲覧

UnityでWhile文の内容が繰り返されるたびにUpdateの内容が行われるようにしたい。

rinmeda317

総合スコア12

C#

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

Unity

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

0グッド

0クリップ

投稿2017/12/02 06:56

編集2017/12/02 06:57

###前提・実現したいこと
Unityで遺伝的アルゴリズムで作成した配列に従ってオブジェクトを移動させたいのですが、適用のさせかたがわかりません。
以下のスクリプトでWhile文の中で作成されたGene[0][]からGene[3][]の四つの配列の内容に従って四つのオブジェクトがそれぞれ移動し、10秒後にオブジェクトの位置をリセットし、次のWhileループに移動してそこで生成された配列でまたオブジェクトを動かし…というのをやりたいのですが、どうすればそれが実現できるのか、手元には入門書程度のものしかなく見当がつきません。
今はとりあえずプレハブで10秒ごとに生成しているのでInvokeを使ってオブジェクトを10秒ごとに消去することでリセットしています。今のスクリプトではエラーは出ていませんがオブジェクトの動きはランダムで、遺伝的アルゴリズムのスクリプトが蛇足となってしまっています。

###該当のソースコード

C#

1 2using System; 3using System.Collections; 4using System.Collections.Generic; 5using UnityEngine; 6 7public class Runbamove : MonoBehaviour { 8 9 // Use this for initialization 10 11 float interval = 1.0f; 12 float timer = 0; 13 14 void Start () { 15 Invoke ("DestroyObject", 10f); 16 } 17 18 //OneMax問題の遺伝的アルゴリズム 19 public void GA() 20 { 21 int[][] Gene = new int[4][];//親の遺伝子 22 int sum = 0; 23 24 for (int i = 0; i < 4; i++)//初期遺伝子の作成 25 { 26 Gene[i] = new int[10]; 27 for (int j = 0; j < 10; j++) 28 { 29 Gene[i][j] = UnityEngine.Random.Range(0, 2); 30 } 31 } 32 33 //配列の中身が全て1になるまで繰り返し 34 while (sum < 10) 35 { 36 37 //評価(配列の中身の合計値が大きい順に並べ替え) 38 int[] keys = new int[Gene.Length]; 39 for (int i = 0; i < keys.Length; i++) 40 { 41 foreach (int e in Gene[i]) 42 { 43 keys[i] -= e; 44 } 45 } 46 Array.Sort(keys, Gene); 47 48 //交叉 49 int[][] NGene = new int[2][];//次世代の遺伝子 50 int p = UnityEngine.Random.Range(0, 10);//交叉する箇所をランダムに決定 51 52 NGene[0] = new int[10];//エリート生存戦略 53 NGene[1] = new int[10]; 54 55 for (int m = 0; m < p; m++)//交叉処理 56 { 57 NGene[0][m] = Gene[0][m]; 58 NGene[1][m] = Gene[1][m]; 59 } 60 for (int n = p; n < 10; n++)//交叉処理 61 { 62 NGene[0][n] = Gene[1][n]; 63 NGene[1][n] = Gene[0][n]; 64 } 65 for (int a = 0; a < 10; a++)//作成した遺伝子を親とする 66 { 67 Gene[2][a] = NGene[0][a]; 68 Gene[3][a] = NGene[1][a]; 69 } 70 71 //突然変異 72 if (Gene[3][p] == 0) 73 {//4番目の遺伝子のうち、p-1番目が0だったら1に変える 74 Gene[3][p] = 1; 75 } 76 77 sum = 0; 78 79 foreach (int s in Gene[0]) 80 { 81 sum = sum + s; 82 } 83 } 84 } 85 86 // Update is called once per frame 87 void Update () { 88 timer -= Time.deltaTime;//時間の取得 89 for(int i = 0; i < 10 ; i++){ 90 if (timer < 0) { 91 int[] Gene = new int [10]; 92 Gene [i] = UnityEngine.Random.Range(0,2); 93 int a = Gene [i];//曲がる方向を配列で決定 94 if (a == 1) { 95 a = -30; 96 } else { 97 a = 30; 98 } 99 Vector3 w = new Vector3 (0f, a, 0f);//回転 100 transform.Rotate (w); 101 timer = interval; 102 } 103 } 104 Vector3 v = new Vector3 (0.5f, 0f, 0f);//移動 105 transform.Translate (v); 106 } 107 108 void DestroyObject(){ 109 Destroy (gameObject); 110 } 111} 112

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

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

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

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

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

guest

回答1

0

ベストアンサー

遺伝的アルゴリズムのスクリプトが蛇足となってしまっています。

この点についてコメントします。おそらく質問者さんは

  • 遺伝的アルゴリズムの計算の経過を表す各世代の結果をUpdateメソッドで利用したい
  • しかしGAメソッドのループ構造はそのままにしたい

ということだと思います。このような場面ではGAメソッドをコルーチンとして実装するとよいと思います。コルーチン(co-routine)はC#固有の機能ではなくプログラミング構造の一種を表す一般用語ですのでwikipediaなどの解説をご覧になるとどのようなものかが伺えると思います。

10秒ごとに云々を抜きにして、GAメソッドで計算する各世代をUpdateでどう利用するかのイメージをコードに表すと次のようになります。

C#

1public class Runbamove : MonoBehaviour { 2 IEnumerator<int[][]> generator; 3 4 void Start() { 5 generator = GA().getEnumerator(); 6 } 7 8 void Update() { 9 if (!generator.MoveNext()) { 10 // これ以上のデータがない=>計算が全て終わった 11 ... 終了処理 ... 12 return; 13 } 14 // GA()メソッドの次の計算結果(yield returnで返されたもの)を取り出して何かする 15 int[][] generation = generator.Current; 16 ... 表示か何かの処理 ... 17 } 18 19 IEnumerable<int[][]> GA() { 20 int[][] gen; 21 ... 22 for (;;) { 23 // 特定の世代の内容を返す。しかしメソッドは完了せず 24 // 次の結果が要求された際にyield returnの次から自動的に継続する! 25 yield return gen; 26 if (目標に到達したら) 27 break; 28 // 29 int[][] nextGen = ... 次の世代の計算 ... 30 gen = nextGen; 31 } 32 // 計算終わり 33 } 34}

上記は純粋なC#のコルーチンの機能をそのまま使ったものですがUnityではこれを拡張し、コルーチン側で「一定秒数待ってから自動的に継続」など、コルーチンが独立して動作するような機構も提供しているようです。

https://docs.unity3d.com/jp/540/Manual/Coroutines.html

おそらくUnityのコルーチンをいきなり読むと「いったいコルーチンって何!?」と感じるのではないかと想像しますが、先に「一般的なコルーチンとは何をするものか」を抑えておくとよいと思います。

コルーチンの動きが実感できてくると「単純なループ構造で書かれた関数を、データを次々と生み出すもの(ジェネレーター)として利用できる」「独立したプログラムの流れを複数並行して動かすことができる=>スレッドを生成せずにスレッド的な動きにできる」といった応用が見えてくると思います。


補足:上のコードが少々わかりにくかったかも知れませんね。コルーチンで実装されたジェネレーターの典型的な使い方はforeachでの利用なのですが、それと対比すると理解しやすいかも知れません。

IEnumerator<T>はT型の要素を列挙する能力を持つ型です。(foreachなどを使うとこの型を直接目にしないため見慣れないかも知れません)。またIEnumerable<T>というのはIEnumerator<T>を生成する能力がある型で大抵のコレクション型(配列, List, Dictionaryなど)はこのインターフェースを備えています。(これはUnityの仕様ではなくC#の標準ライブラリーの仕様です)

C#

1IEnumerable<T> GetGenerator() { ... } 2 3//(1) foreachで利用する方法 4foreach (T element in GetGenerator()) { 5 ... elementに対する処理 ... 6} 7 8//(2) 上記と同じことを別の書き方で書くと 9IEnumerator<T> enumerator = GetGenerator().getEnumerator(); // (A) 10while (enumerator.MoveNext()) { // (B) 11 T element = enumerator.Current; 12 ... elementに対する処理 ... 13}

(1)が典型的な使い方ですが、これではUpdateの1回の呼び出しで1世代のみを取り出すことができません。そこで(2)の方法に着目します。(2)なら「まだ次の要素があるかをMoveNext()で調べ、もしあるならその要素をCurrentでアクセスする」というのをUpdateの中で1回だけ行えます。(A)はIEnumerableの計算を開始するためのコードのため上の例ではStartに置きましたが、なんども繰り返しGAを実行したいなら、適当なタイミングで(Startメソッド以外の場所で)
generator = GA().getEnumerator();
とすれば何度でも新たな列挙をやりなおせます。

投稿2017/12/02 10:01

編集2017/12/03 15:43
KSwordOfHaste

総合スコア18394

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

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

rinmeda317

2017/12/03 06:25

回答ありがとうございます。コルーチンの存在を知らなかったので助かりました。 スクリプトまで載せていただいたのはありがたいのですが、StartとUpdateで何が行われているのかがいまいちよくわからないので、差し支えなければもう少し詳しく教えていただけないでしょうか?
rinmeda317

2017/12/03 15:31

丁寧に補足していただきありがとうございます。 まだ完全には理解しきれていませんが、こちらでも色々と調べてみます。 前回の質問に引き続き付き合ってくださってありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問