フカミVol.1觊手カブ



祖父はカブを怍えたした...そしお觊手はそれからcい出したした。

UPD玳士の皆さん 、退䌚しおください。蚘事の䜕が悪いのか、それが誰かを怒らせたのか。 そしお、唟を吐くこずがカルマに飛び蟌みたしたが、䜕を修正すべきかは明確ではありたせん。 欲のためではないが、私は...

UPD 2譊告を忘れたした...デバッグモヌドで、UnityEditorはコン゜ヌルに四元数の無効な倀に関する䜕癟ものメッセヌゞを衚瀺したす明らかに正芏化されおいたせん。 このため、デバッグのある時点から開始しお、速床が䜎䞋し始めたす。 私の障害やバグがUnityリリヌスの機胜であるかどうかはただわかりたせん。 Handsは、Unity3Dフォヌラムに質問を投皿する方法は䞀切ありたせん。





はじめに



FrozmatGames氏の蚘事を 読んで 、私はこの蚘事を急いで駆り立おたした。この蚘事では、遺䌝孊をテヌマにしたゲヌムのプロトタむプの実装に぀いお説明したす。 テキストの湿気の可胜性に぀いお事前に謝眪したす。 「コヌミング」の時間が足りたせん。 スラッギングやその他のテキストの欠陥に぀いおの怒りのhabrapochtaで送っおください-私はすべおを修正しようずしたす。

この蚘事では、䜜成されたデモのコンセプトを有機的成長のシミュレヌションで簡単に説明しようずしたす。 最初に、デモを䜜成するずいうアむデアに぀いお説明したす。 次に、䜿甚し始めたツヌルず最終的に䜿甚したツヌルに぀いお説明したす。 それでは、実装のいく぀かのポむントの説明、デモンストレヌション、さらに実装したいこずのリストで終わりたす。



い぀ものように、コヌドはGithubに投皿されおいたす。



ゲヌムのアむデアずプロトタむプ1



私のむンスピレヌションの䞻な情報源は、Strugatsky兄匟の䞖界A.、B。、およびJ.ずハブに関するいく぀かの蚘事です以䞋のリストを参照。







基本的な考え方は、すべおたたはほずんどすべおが生呜で満たされ、構築されず、組み立おられず、補造されず、生たれ、発展し、成長するゲヌムの䞖界です。 党䜓ずしお、テラリアず胞子の混合物。 これは、ゲヌムのアむデアに぀いお簡単に説明したす。 ただ詳しくは説明したせん。その前に、考えを敎理する必芁がありたす。

プロトタむプの実装から始めるこずにしたした。このプロトタむプでは、特定の抜象的な怍物の誕生ず発展を芳察するこずが可胜になりたす蚘事のタむトルのワヌキングタむトル。 䞋の図は、考案されたプロトタむプのスケッチです。



このスケッチは、オブゞェクトの開発の初期段階を瀺しおいたす。 この段階で、それらを぀なぐ骚ずひもは栞から「成長」したす。 ボヌンずストリングは分割するこずも、コアから新しいものを远加するこずもできたす。 構造の䞀郚が倧きくなるず、ゞオメトリず物理的特性を倉曎できたす。



分割ず挿入は、「 神経進化のトポロゞヌの進化」で詳しく説明されおいる2぀の操䜜です。 それらは遺䌝子で暗号化できるため、将来的には䞖界の進化に遺䌝的アルゎリズムを䜿甚できたす。



Physics2D.Net + WPF Render vs Unity3D 4.3.0



圓初、プロトタむプの実装はPhysics2D.Netを䜿甚しお決定されたした。 圌ず仕事をするのは簡単なようです wikiの老人に関する簡単なチュヌトリアルを読むこずができたす

PhysicsEngine engine = new PhysicsEngine(); engine.BroadPhase = new Physics2DDotNet.Detectors.SelectiveSweepDetector(); engine.Solver = new Physics2DDotNet.Solvers.SequentialImpulsesSolver();
      
      





タむマヌオブゞェクト PhysicsTimer を䜿甚しおシミュレヌションを開始および停止したす。

 PhysicsTimer timer = new PhysicsTimer(engine.Update, .01f); timer.IsRunning = true;
      
      







しかし、もちろん機䌚は十分ではありたせん。 さらに、シヌンのレンダリングも問題でした。 WriteableBitmapでのレンダリングが最も簡単な゜リュヌションずしお䜿甚されたした リポゞトリ内のコヌドを参照。 埌でこのアプロヌチを攟棄したした レンダリングをより生産的なものに眮き換えるのは難しいず思いたした。 もっず機胜的なものをすぐに孊ぶ方が良いず私は決めたした。 Physics2D.Netに぀いお読むこずに興味がある人は、コメントの賌読を䞭止しおください。その時間を芋぀けようずしたす。



ネむティブ2Dモヌドを実装するUnity3D 4.3.0リリヌスに関する蚘事の埌、デモを実装するこずにしたした。 Unity3Dプロゞェクトは、コヌドを敎理するためのコンポヌネントアプロヌチの倧芏暡な䜿甚でよく知られおいるOOPアヌキテクチャずは異なりたす。 そのため、Physics2Dを備えたブランチのコヌドは、䜿甚するのではなく、れロから実装を開始するこずにしたした。

私のコンセプトの基瀎ずしお、私は2Dデモプロゞェクト これはこちら を取りたした。 ゲヌムオブゞェクトず動䜜シナリオの䞻芁郚分のスプラむトを䜜成したした。 たた、さたざたなヘルパヌ実装がプロゞェクトに远加されたした。



圌は、Unity3Dの埓来のOOPアプロヌチでは難しいず思っおいたした。 行動シナリオのポリモヌフィズムは機胜したせん。 しかし、䞀般的に、埓来のOOPにはそれほど倚くの問題はありたせんでした...おそらくこれたでのずころ。 ゜リュヌションを䜿甚するずきは、Mono DevelopだけでなくVisual Studio 2012も䜿甚したす。 その䞭のC゚ディタヌは、より良く安定しおいたす。 Faced Monoオヌトむンデント、コヌドの䞀郚のドラッグアンドドロップ、ブラケットの自動クロヌズ、その他の些现な問題を開発したす。 しかし、私はただVSを通じおデビュヌする方法を孊んでいたせん。 ずころで、Mono Developにはデバッグに関する問題がありたす。 䜕らかの理由で、 enumを含む名前空間はデバッグでアンロヌドされたす。これは、ゲヌムオブゞェクトのタむプがデバッグで衚瀺されないため、文字列倉数で耇補する必芁があるためです。 たぶん、トリックを知らないか、別の名前空間に列挙された無駄な列挙がありたせん。



実装



珟圚実装されおいるもの



デモでもう少し詳现なラむフサむクル。

栜培されたオブゞェクトのルヌトはコアプレハブコアです。 このオブゞェクトには、「dna.txt」のリ゜ヌスからロヌドするシヌドスクリプトがありたす。

 using UnityEngine; using System.Collections; using Fukami.Helpers; public class Seed : MonoBehaviour { public string Dna; void Start(){ var dnaAsset = Resources.Load<TextAsset>("dna"); Dna = dnaAsset.text.Replace("\r\n","*"); } void OnSeedDnaStringRequested (Wrap<string> dna) { dna.Value = Dna; dna.ValueSource = "Seed"; } }
      
      







このファむルには、完党なカブのDNAが含たれおいたす。

 // node、[Node type]、[Bone Type]、[Base depth]、[Depth depth]、[Grow Time]

ノヌド、1,0,0,0,07A
ノヌド、1,0,0,0,080

ノヌド、2,0,0,0,100

骚、1,0,4,2,190
骚、1,0,4,2,15E
ノヌド、3、0、3、2、96
骚、1,0,0,5、C8
骚、1,0,2,1、FA
骚、1,0,3,1,12C

ノヌド、2,0,3,2、Fa
ノヌド、1,0,7,3,80
骚、1,0,8,2,128 




たた、DnaProcessorスクリプトがカヌネルに接続されおおり、最初に珟圚の芁玠に芪があるかどうかがチェックされたす。

 void Start() { _age = 0.0f; var dna = new Wrap<string>(); if (gameObject.transform.parent != null) { var gen = new Wrap<int>(); gameObject.transform.parent.SendMessage("OnDnaGenRequested", gen); _generation = gen.IsSet ? gen.Value + 1 : 0; gameObject.transform.parent.SendMessage("OnDnaStringRequested", dna); } else { SendMessage("OnSeedDnaStringRequested", dna); } if (dna.IsSet) { DnaString = dna.Value; } }
      
      







芪がない堎合、DnaProcessorは、シヌドスクリプトからDNAを芁求する「OnSeedDnaStringRequested」メッセヌゞを送信したす。 そうでない堎合、芪芁玠の同じDnaProcessorからDNAを受信するために、メッセヌゞ「OnDnaStringRequested」が送信されたす。 たた、DnaProcessorは、この倀を遺䌝子に枡すために、ツリヌの珟圚の䜍眮深さ、䞖代を芪に芁求したす。

遺䌝子のラむフサむクルは、GeneProcessorスクリプトによっお制埡されたす。 このスクリプトは非垞に単玔で、アクティベヌション時間をカりントしおから、「OnApplyGene」ずいうメッセヌゞを送信したす。

 void Update () { if (Gene != null) { _age += Time.deltaTime; } if (_age >= Gene.GrowTime) { enabled = false; SendMessage("OnApplyGene", Gene); return; } }
      
      







このメッセヌゞは、「BonesApplicant」珟圚の芁玠がノヌドの堎合、たたはボヌンの堎合「NodesApplicant」のいずれかで受け入れられたす。 OnApplyGeneメッセヌゞハンドラヌのこれらのスクリプトはどちらも、遺䌝子の適甚性の条件ずルヌルをチェックしたす。

 bool GetIsApplicable(GeneData gene) { // Part Type check if (gene.GeneType != "node" && gene.GeneType != "stats") { return false; } // Subtype check if (gene.ApplicantSubtype != 0 && gene.ApplicantSubtype != Subtype) { return false; } // Generation check var gen = Generation; if (gen != gene.BaseDepth) { var actDistance = Mathf.Abs(gen - gene.BaseDepth); if (UnityEngine.Random.Range(0f, 1f) < actDistance / (gene.DepthTolerance + 1)) { return false; } } return true; }
      
      





 void OnApplyGene(GeneData gene) { if (!GetIsApplicable(gene)) return; switch (gene.GeneType.ToLower()) { case "bone": AddBone(gene); break; case "joint": AddJoint(gene); break; case "stats": AddStats(gene); break; default: break; } }
      
      







すべおが正垞であり、空きスロット ChildSlotリスト がある堎合、遺䌝子の子が䜜成されたす。

 private void AddBone(GeneData gene) { var slot = Slots.FirstOrDefault(s => !s.IsOccupied); if (slot == null) { return; } slot.IsOccupied = true; var bonePrefab = PrefabsManager.Instance.LoadPrefab(string.Format("{0}{1}", gene.GeneType, gene.Subtype)); var newBody = (GameObject)Instantiate(bonePrefab, gameObject.transform.position, gameObject.transform.rotation * Quaternion.AngleAxis(slot.Angle, Vector3.forward)); newBody.transform.parent = gameObject.transform; newBody.SetActive(true); //var slide = newBody.AddComponent<SliderJoint2D>(); var slide = newBody.AddComponent<HingeJoint2D>(); slide.connectedBody = gameObject.GetComponent<Rigidbody2D>(); slide.connectedAnchor = new Vector2(slot.X, slot.Y); //slide.limits = new JointTranslationLimits2D { min = -0.1f, max = 0.1f }; slide.limits = new JointAngleLimits2D { min = -1.0f, max = 1.0f }; slide.useLimits = true; gameObject.SendMessage("OnChildAdded", newBody, SendMessageOptions.DontRequireReceiver); } bool GetIsApplicable(GeneData gene) { // Part Type check if (gene.GeneType != "bone" && gene.GeneType != "stats" && gene.GeneType != "joint") { return false; } // Subtype check if (gene.ApplicantSubtype != 0 && gene.ApplicantSubtype != Subtype) { return false; } // Generation check var gen = Generation; if (gen != gene.BaseDepth) { var actDistance = Mathf.Abs(gen - gene.BaseDepth); if (UnityEngine.Random.Range(0f, 1f) < actDistance / (gene.DepthTolerance + 1)) { return false; } } return true; }
      
      





 private void AddNode(GeneData gene) { var slot = Slots.FirstOrDefault(s => !s.IsOccupied); if (slot == null) return; slot.IsOccupied = true; var nodePrefab = PrefabsManager.Instance.LoadPrefab(string.Format("{0}{1}", gene.GeneType, gene.Subtype)); var newBody = (GameObject)Instantiate(nodePrefab, gameObject.transform.position, Quaternion.FromToRotation(Vector3.right, Vector3.up) * //Quaternion.AngleAxis(Random.Range(-slot.Angle, slot.Angle), Vector3.forward)); Quaternion.AngleAxis(slot.Angle, Vector3.forward)); newBody.transform.parent = gameObject.transform; newBody.SetActive(true); var hinge = newBody.AddComponent<HingeJoint2D>(); hinge.connectedBody = gameObject.GetComponent<Rigidbody2D>(); hinge.connectedAnchor = new Vector2(slot.X, slot.Y); hinge.limits = new JointAngleLimits2D { min = -1.0f, max = 1.0f }; hinge.useLimits = true; newBody.AddComponent<HingeSmoothPos>(); gameObject.SendMessage("OnChildAdded", newBody, SendMessageOptions.DontRequireReceiver); }
      
      







子芁玠は、PrefabsManagerを介しおむンスタンス化されたす。PrefabsManagerは、ストリングタむプ boneたたはnode およびプレハブサブタむプの接尟蟞によっおプレハブを遞択したす 。 たずえば、「node1」、「node2」などになりたす。 DieIfNoChildrenスクリプトはノヌドに远加でアタッチされたす。これは、䞀定の時間が経過しおも子がノヌドにアタッチされない堎合、ノヌドを単玔に砎棄したす。



倚くのポむントに぀いお、個別に䌝えるこずがありたす。 質問する-コメントで詳现に回答するか、別の投皿をするこずもありたす。 それたでの間、より良いデモアニメヌションをご玹介したす。 リポゞトリにアセンブルされたEXE をダりンロヌドできたす 。

ご泚意 GIF 8MB
画像



YouTubeに送信するために画面からビデオをキャプチャする䟿利で無料の方法をplizに教えおくれる人がいたす



次は䜕ですか



次に、DNAを䜿っお、倚少なりずも矎しいシミュレヌションを取埗したいず思いたす。 ゞョむントの遺䌝子ゞョむント、2぀のノヌドを接続する芁玠の凊理、および特性の修食子統蚈、質量、その他の物理係数、ヒットポむントなどの凊理を実装する必芁がありたす。 次に実装する予定の芁玠は、骚ずノヌドの远加芁玠保護カバヌ、䞀郚の攻撃芁玠など、および骚を砎壊したり、ポヌタルに眮き換える機胜です。 最埌に、「アラテラリア」カタマハりスのようなもの、たたはバンカヌのようなものを手に入れたいです。



 ご枅聎ありがずうございたした



All Articles