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

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

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

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

Unity

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

Q&A

解決済

1回答

6625閲覧

C#で遺伝的アルゴリズムの組み方がいまいちわかりません

rinmeda317

総合スコア12

C#

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

Unity

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

0グッド

0クリップ

投稿2017/11/25 09:19

編集2017/11/25 11:05

###前提・実現したいこと
大学生です。
Unityで遺伝的アルゴリズムを利用して2Dタワーディフェンスゲームを作ろうとしているのですが、C#に触れるのが初めてなもので、理論は理解していてもどうスクリプトを組めばいいのかわからず、スクリプト例を見ててわからなかった用語(IEnumerable、yield、paramなど)をネットなどで調べても専門用語ばかりで理解ができず、難航しています。

実装したい機能の流れとしては、
・プレハブでオブジェクトを10個作成し、一定間隔で右折もしくは左折させて移動させるために0なら右折、1なら左折というように0と1の配列を作成して読み込ませる
・世代終了時に最もx座標値が大きかった2個体を選択
・一点交叉をして次世代の10個体の配列を作成する
・作成した配列をもう一度新しくプレハブで作成したオブジェクトに適用する
・x座標値が一定の値を超えたら終了
というものを想定しています。

現時点で実現したいもののできていないことは大体以下の通りです。

・プレハブで作成したオブジェクト"Runba"に番号を振りたい
・各Runbaが保持する配列を別のスクリプトに渡したい。
・配列のメソッドの呼び出し方がわからない。

他にもまだまだ課題はありますが、まず解決しなければならないのはこのあたりだと思います。
ソースコードは書きかけゆえ不完全で煩雑なものですし、上記の文章もわかりづらい表現になってしまっていることは承知の上ですが、私一人の力ではもうどうすることもできません。どうかよろしくお願いします。

追記
RunbaGenerator.csの「obj.name = Runba.name」を「obj.name = "Runba" + i」と書き換えてみたら一つ目の問題は解決しました。

###発生している問題・エラーメッセージ

エラーメッセージ Assets/Runbamove.cs(25,13):error CS0103:The name 'Gene' dose not exist in the current context これを解消するために何を追加で記入するべきかがわかりません

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

C#

1 2//RunbaGenerator.csの内容 3using System.Collections; 4using System.Collections.Generic; 5using UnityEngine; 6 7public class RunbaGenerator : MonoBehaviour { 8 9 public GameObject Runba; 10 float span = 10.0f; 11 float timer = 0; 12 13 // Use this for initialization 14 void Start () { 15 } 16 17 //初期遺伝子の作成 18 public int[] OriginGene () { 19 int[] Gene = new int [10]; 20 for(int i = 0; i < 10 ; i++){ 21 Gene [i] = Random.Range(0,2); 22 } 23 return Gene; 24 } 25 26 // Update is called once per frame 27 void Update () { 28 timer -= Time.deltaTime;//時間の取得 29 if (timer < 0) { 30 for (int i = 1; i < 11; i++) { 31 GameObject obj = Instantiate (Runba, new Vector3 (50, 1, i * 90), Quaternion.identity) as GameObject;//生成 32 obj.name = Runba.name;//生成されたオブジェクトの名前をRunbaに変更 33 } 34 timer = span;//タイマーをリセット 35 } 36 } 37} 38 39//Runbamove.csの内容 40using System.Collections; 41using System.Collections.Generic; 42using UnityEngine; 43 44public class Runbamove : MonoBehaviour { 45 46 // Use this for initialization 47 48 float interval = 1.0f; 49 float timer = 0; 50 51 void Start () { 52 Invoke ("DestroyObject", 10f); 53 GetComponent<RunbaGenerator>().OriginGene(); 54 //Gene[] = 55 } 56 57 // Update is called once per frame 58 void Update () { 59 timer -= Time.deltaTime;//時間の取得 60 for(int i = 0; i < 10 ; i++){ 61 if (timer < 0) { 62 int a = Gene [i];//曲がる方向を配列で決定 63 if (a == 1) { 64 a = -30; 65 } else { 66 a = 30; 67 } 68 Vector3 w = new Vector3 (0f, a, 0f);//回転 69 transform.Rotate (w); 70 timer = interval; 71 } 72 } 73 Vector3 v = new Vector3 (0.5f, 0f, 0f);//移動 74 transform.Translate (v); 75 76 /*bool f0 = Input.GetMouseButton (0);//クリック時の反応 77 if (f0) { 78 Vector3 V0 = Input.mousePosition; 79 V0.z += 3f; 80 Ray ray = Camera.main.ScreenPointToRay (V0); 81 RaycastHit hit; 82 bool f = Physics.Raycast (ray, out hit, 1000); 83 if (f) { 84 if (hit.collider.gameObject.name == "Runba") { 85 gameObject.SetActive(false);//クリックされた場合ルンバを非表示 86 } 87 }//現行での問題点:クリックするとクリックしたものより左側のルンバも全部消える 88 }*/ 89 } 90 91 //今世代のGene[]を10個取得してGeneAlgorithm.csに渡すためのメソッド 92 public int[] Genetic(){ 93 94 } 95 96 void DestroyObject(){ 97 Destroy (gameObject); 98 99 } 100}

###試したこと
課題に対してアプローチしたことを記載してください

###補足情報(言語/FW/ツール等のバージョンなど)
Unityのバージョンは最新です

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

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

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

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

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

MasahikoHirata

2017/11/25 09:49

まずはエラーの意味を理解されるのが良いかと。’public int[] OriginGene () ’の内部変数の’Gene'が関数’Runbamove’から見えないから’何?’と言われていると思いますが。
rinmeda317

2017/11/25 10:23

内部変数の読み込みのために追加で何かを書かなければいけないのは理解しています。何を記入すればいいのかがわからないのです…
guest

回答1

0

ベストアンサー

Unityで遺伝的アルゴリズムを利用して
2Dタワーディフェンスゲームを作ろうとしている

質問者の方にとって、魅力的な題材なのは分かります。
遺伝的アルゴリズム(GA)」とかって、
生物の世代交代の仕組みを利用するコンセプトが面白いですよね。

しかし、難しいことをいっぺんにやろうとしている感じです。

C#、Unity、遺伝的アルゴリズム、タワーディフェンス、
どれも一冊の本になるくらいのテーマです。

最初はUnity抜きでC#の仕様だけ見てみるとか、
逆にUnityを学ぶときはまずUIだけいじってみるとか、
遺伝的アルゴリズムをやるなら、ゲーム部分はジャンケンにするとか、
逆にタワーディフェンスをやるなら、GAは抜きにするとか、
問題を分けて小さくして、各個撃破していきましょう。

個々のテーマに分解して、それぞれ集中して学ぶ方が、
最終的な成功率は高いでしょう。たとえると、急がば回れ。ウサギとカメ。


さて、上記だけだと、一般論だけでお茶を濁されているように
感じているかもしれませんから、プログラミングについても触れます。

ご自分で書いたコードなのに、自分で読んでも分かりにくいと思います。
だから、こうして質問しているんでしょう。

専門用語ばかりで理解ができず、難航しています。

質問者の方が自覚されているように、
仕様の理解不足という面がまずあるでしょう。


しかし、仕様とコードを分けて考えているでしょうから、あえて言うと、
コードと仕様を近づけていく、という発想に欠けています。

C#はオブジェクト指向言語ですので、OOPに向いています。
OOには、高凝集・疎結合とか、単一責務などの原理原則があります。

そこで、遺伝的アルゴリズムは、タワーディフェンス(たとえば回転や移動)と、
まったく別の関心事、別のドメインですから、クラスも分けます。

そして、「遺伝子」、「世代」、「交叉」、「淘汰」、「突然変異」など、
ドメインの用語に合わせて、フィールドやメソッドを作ります。

現状でも、「初期遺伝子の作成」「OriginGene」とかはありますが、
それだけでは不十分なので、さらに分離してください。責務を分離します。

そうしたら、タワーディフェンスのキャラクターのクラスからは、
GAの自作ライブラリを使う感じにします。つまり、内部の実装には触れない。

さらに言うと、GAライブラリは移動や回転をしている部分からは呼ばず、
なるべくファクトリから(だけ)使うことを考えます。
GAを使う以上、複数キャラを作るはずで、生成と相性が良いからです。

なお、最近のGAは、たとえば島に分けるとか、いろいろ工夫しており、
複雑になるようなら、名前空間(Javaでいうパッケージ)の単位で、
より大きくグループ化しても良いでしょう。というか、私なら分けちゃうかも。


もし、そうした方が上手くいくかどうか、疑問が残るようでしたら、
(クラス)ライブラリを使った経験に、照らし合わせてみてください。

いろんな言語の標準ライブラリで、
日付と画像を混ぜたり、数学とファイル操作を混ぜたり、
といったことは、まずありえないと思います。ないでしょ?

じゃあ、自分で作るクラスでも同様に
遺伝的アルゴリズムとタワーディフェンスを分けた方が、
使いやすいのではないでしょうか。

分割統治はプログラミングの王道です。
人間は一度に二つ以上のことを同時に考えるのが難しいので、
まして難しい専門領域なら、分けることをまず考えてください。
分けると分かりやすいので、コード上でも分けてください。

もちろん、分ける手間はありますが、デバッグの方が手間です。
どうせ今のバグを取りのぞいても、すぐ別のバグが湧いてきますから、
徹底的に分離してテストを書いた方が、結果的には早くできると思います。

最後に、今回の回答で設計の話を中心にしたのは、GAを使うレベルまで来ると、
ソースのIF文やFor文を追うだけでは対処療法でしかなく、
全体の設計ができてないと、正しく動かすのが難しいからです。

投稿2017/11/25 11:21

編集2017/11/25 11:44
LLman

総合スコア5592

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

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

rinmeda317

2017/11/25 12:19 編集

回答ありがとうございます。 確かにいっぺんにやるのは無理だと私も感じており、ゲーム云々は置いといてまずは遺伝的アルゴリズムに絞ってやろうとしているところです。 さらに分離、ということはOriginGeneはルンバの挙動を制御するRunbamoveやプレハブでルンバを作成するRunbaGeneratorのクラスとは別の場所に書いた方がいいということでしょうか?
LLman

2017/11/25 12:38

>別の場所に書いた方がいいということでしょうか? 結論から言うとそうですが、 たんに場所が別というだけでなく、完全に独立させます。 「Runba」云々の名前や参照が入ってこないようにします。 GAのドメインにそんな概念はないからです。 しかしこれは、GAが難しいから分かりにくいかも。そこで、単純な例で考えてみます。 たとえば、最新の日付のファイルを読み込むときに、 日付とファイル操作の(クラス)ライブラリ自体は別々で、それを組み合わせて使う、 自作ライブラリを書くにしても、日付とファイル操作は別々に作る、 という例なら抵抗なく受け入れられると思うんですよ。 GAも完全に分離しちゃって、タワーディフェンスの要素が 【一切入らない】形で作ってしまって大丈夫です。 タワーディフェンス以外にも使えるようになるので、むしろその方が使いやすいです。 だって、言語の標準ライブラリはすでに使っておられるでしょうが、 文字列操作とかに、ゲームの要素とか、一切入っていないですよね? ゲームで文字列が必要だとしても、外からAPIを叩くだけですよね? だから、GAを書くときは、タワーディフェンスのことをスッパリ忘れてしまって、 まず独立したライブラリとかAPIにすることを、念頭に置いて作りましょう。 そして、使うときに中を見なくてもよくなるまで抽象化します。 だって、標準ライブラリは中を見なくても使えますから。 このOO的なやり方だと、デバッグやテストが劇的に楽になるので、 とくに難しいと感じる専門領域は、ライブラリ化しましょう。
rinmeda317

2017/11/25 12:53

言葉が足りず申し訳ありません、遺伝的アルゴリズムは遺伝的アルゴリズムでGeneAlgorithm.csという名前のファイルで独立させて書くつもりであり、只今その方向でスクリプトを組もうとしているところです。 そこで配列の仕様がわからないという壁に当たりました。
LLman

2017/11/25 13:10

>配列の仕様がわからない それなら、GAを組む前に、C#の仕様を少し調べると良いと思います。 C#はメジャーな言語で情報も多いので、ネットや本で調べてください。 結局、理解が中途半端なままだと、GAが原因か、C#が原因か、 問題が混ざってしまって、また別の機会にデバッグで苦しみますから。 今、目の前で詰まってる部分だけが気になるでしょうが、調べた方が早いです。 たとえると、かけ算の九九を飛ばして、いきなり微積分ができないように、 GAレベルをやるなら、配列のような基本仕様くらいは、押さえておきましょう。
rinmeda317

2017/11/25 13:40

ですよね…新たに本を探して調べるとします。 拙い日本語ながら付き合ってくださって本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問