Unity3D 正六邊形,環狀擴散,緊密分布,的程序

最近在做一個正六邊形的遊戲,被一開始的布局難倒了。

需求:中心有個正六邊形,輸入圍繞中心擴散的環數,自動創建和擺放。

大概就是這樣的吧,我覺得這個非常輕鬆的就可以搞定了。啊~~~~~啊~~~ 五環~~,你比四環多一環,啊~~~~啊~~~五環~~,你比六環少一環~~~

可是,到底每環要放多少個六邊形?經過我縝密的觀察發現一個規律。

如果假設第一個環編號為1,那麼每個換六邊形的數量就是 環數*6。啊~~~~~啊~~~ 五環~~,一環就是紫~禁~城~~~~。

可是擺放的具體位置是哪裡?既然是圓形,那就需要知道 角度半徑 就可以依據圓形坐標公式算出來了。

二維圓上的點坐標公式:

X = Mathf.Sin(角度*Mathf.PI/180) * 半徑

Y = Mathf.Cos(角度*Mathf.PI/180) * 半徑

有人可能問,上面寫的公式原理是啥?哈~哈~哈~~~~

我也是---

啊~~~~~啊~~~ 五環~~,你比四環多一環,啊~~~~啊~~~五環~~~~~~

參見:已知圓心,半徑,角度,求圓上的點坐標 - - 博客頻道 - CSDN.NET

-----半徑是啥?

緊密擺放的話,半徑就是六邊形的寬度。而每一環的半徑就是環數*第一個半徑。

好了這個可以大概構建一個循環體了。

=========下面搭建循環體============

Int RoundMax = 10;//最大環數變數

float Radius = 1f;//六邊形最短寬度

for(int round = 1;round<=RoundMax;round++)//每一層環的循環體

{

for(環上每個六邊形循環體)

Vector2 = new Vector2(Mathf.Sin(角度*Mathf.PI/180) * Radius * round, Mathf.Cos(角度*Mathf.PI/180) * Radius * round);

}

}

===============

那麼角度又是多少?

360 ÷ 每一環的總數 = 間隔的角度

間隔的角度 × 當前序號 = 當前角度

=========下面添加每一環的計算程序============

Int RoundMax = 10;//最大環數變數

float Radius = 1f;//六邊形最短寬度

for(int round = 1;round<=RoundMax;round++)//每一層環的循環體

{

for(int id = 0; id<=round*6; id++)//當前環的總個數 = round*6

{

Vector2 Pos= new Vector2(

Mathf.Sin(360/(round*6)*id*Mathf.PI/180) * Radius * round,

Mathf.Cos(360/(round*6)*id*Mathf.PI/180) * Radius * round

);

}

}

=======下面轉為三維向量========

Int RoundMax = 10;//最大環數變數

float Radius = 1f;//六邊形最短寬度

for(int round = 1;round<=RoundMax;round++)//每一層環的循環體

{

for(int id = 0; id<=round*6; id++)//當前環的總個數 = round*6

{

Vector3 Pos= new Vector3(

Mathf.Sin(360/(round*6)*id*Mathf.PI/180) * Radius * round,

0,

Mathf.Cos(360/(round*6)*id*Mathf.PI/180) * Radius * round

);

}

}

=====距離勝利還有一步 下面引入模型和創建========

GameObject Zero_OBJ;//六邊形物體

Int RoundMax = 10;//最大環數變數

float Radius = 1f;//六邊形最短寬度

for(int round = 1;round<=RoundMax;round++)//每一層環的循環體

{

for(int id = 0; id<=round*6; id++)//當前環的總個數 = round*6

{

Vector3 Pos= new Vector3(

Mathf.Sin(360/(round*6)*id*Mathf.PI/180) * Radius * round + ,

0,

Mathf.Cos(360/(round*6)*id*Mathf.PI/180) * Radius * round

);

Instantiate(Zero_OBJ,

Zero_OBJ.transform.position.+ Pos ,//依據物體坐標偏移

Quaternion.identity);

}

}

=======哈哈哈 我是在佩服我的智慧========

天空飄來五個字 那都不是事

運行結果

我去~~~真圓~~~~~

接下的十幾分鐘...

=================然後開始奮發圖強的思考=============

其實還是有幾個擺放正確的六邊形

也就是說除了這0 , 60,120 , 180 , 240 , 300 角度的六邊形,其餘六邊形其實不是正圓分布,而是直線分布。

如果是直線分布,就需要依據兩點的坐標計算出排列的矢量方向,然後依據半徑擺放就可以了。

=====接下吧正確位置寫入 Pos_6[]========

GameObject Zero_OBJ;//六邊形物體

Int RoundMax = 10;//最大環數變數

float Radius = 1f;//六邊形最短寬度

for(int round = 1;round<=RoundMax;round++)//每一層環的循環體

{

Vector3 [] Pos_6 = new Vector3[6];//記錄正確6個位置的數組

for(int id = 0; id<= 6; id++)//當前環的總個數 = round*6

{

Pos_6[i] = new Vector3(

Mathf.Sin(360/(round*6)*id*Mathf.PI/180) * Radius * round + ,

0,

Mathf.Cos(360/(round*6)*id*Mathf.PI/180) * Radius * round

);

Instantiate(Zero_OBJ,

Zero_OBJ.transform.position.+ Pos_6[i] ,//依據物體坐標偏移

Quaternion.identity);

}

}

中間的六邊形個數規律是:

每個六邊形偏移距離是:

=======接下來插入之間的六邊形========

GameObject Zero_OBJ;//六邊形物體

Int RoundMax = 10;//最大環數變數

float Radius = 1f;//六邊形最短寬度

for(int round = 1;round<=RoundMax;round++)//每一層環的循環體

{

Vector3 [] Pos_6 = new Vector3[6];//記錄正確6個位置的數組

for(int id = 0; id<= 6; id++)

{

Pos_6[i]= new Vector3(

Mathf.Sin(360/(round*6)*id*Mathf.PI/180) * Radius * round + ,

0,

Mathf.Cos(360/(round*6)*id*Mathf.PI/180) * Radius * round

);

Instantiate(Zero_OBJ,

Zero_OBJ.transform.position+ Pos_6[i] ,//依據物體坐標偏移

Quaternion.identity);

}

if(round >1)//第2圈開始執行插入

{

for(int id = 0; id<= 6; id++)//逐個區間插入

{

int NextID =( id+1)%6;//獲取下一個位置ID,在0~5中循環取值

Vector3 Orientation = Vector3.Normalize(Pos_6[NextID]-Pos_6[id])//單位朝向(下一個點-當前點)

for(int addID = 1;addID <round;addID ++)//循環插入

{

//----------插入點 = 單位方向*當前偏移距離+起點偏移

Vector3 Insert_Pos =

Orientation

*(Radius * addID )

+( Pos_6[addID ] + Zero_OBJ.transform.position);

//-------------------------------------------------------------

Instantiate(Zero_OBJ,Insert_Pos ,Quaternion.identity);

}

}

}

}

========運行結果===========

如果有更簡單的方法,求賜教。

========我整理後的程序=========

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class PlacingHexagon_CRomputer : MonoBehaviour {

tpublic GameObject Zero_OBJ;//六邊形物體

tpublic int RoundMax = 10;//最大環數變數

tpublic float Radius = 1f;//六邊形最短寬度

tprivate Vector3 [] Pos_6 = new Vector3 [6];//記錄6個位置的數組

t// Use this for initialization

tvoid Start () {

ttInstantiate(Zero_OBJ, transform.position ,tQuaternion.identity);//創建中心物體

ttfor(int round = 1;round<=RoundMax;round++){//每一層環的循環體

tttfor(int id = 0; id < 6; id++){//放置每一環的頂點物體

ttttPos_6 [id] = new Vector3(Mathf.Sin(60*id * Mathf.PI / 180) * Radius * round , 0f , Mathf.Cos(60*id * Mathf.PI /180) * Radius * round) + transform.position ;//記錄6個正確位置

ttttInstantiate(Zero_OBJ, Pos_6[id] , Quaternion.identity);//生成物體

ttt}

tttif(round >1)//第2圈開始執行插入

ttt{

ttttfor(int id = 0; id < 6; id++)//逐個區間插入物體

tttt{

tttttint NextID =( id+1)%6;//獲取下一個位置ID,在0~5中循環取值

tttttVector3 Orientation = Vector3.Normalize( Pos_6[NextID]-Pos_6[id] );//單位朝向(下一個點-當前點)

tttttfor(int addID = 1; addID < round ; addID++) //循環插入

ttttt{

ttttttVector3 Insert_Pos = Orientation *(Radius * addID)+Pos_6[id];//插入點 = 單位方向*當前偏移距離 + 起點偏移

ttttttInstantiate(Zero_OBJ,Insert_Pos ,Quaternion.identity); //生成中間物體

ttttt}

tttt}

ttt}

tt}

t}

t// Update is called once per frame

tvoid Update () {

t}

}

========@鄧浩給出的遞歸思路=========

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class PlacingHexagon_DengHao : MonoBehaviour {

tpublic GameObject Zero_OBJ;//六邊形物體

tpublic int RoundMax = 10;//最大環數變數

tpublic float Radius = 1f;//六邊形最短寬度

tprivate List<Vector3> Hexagon_List =new List<Vector3>();//已創建位置列表

tvoid Placing(int n,Vector3 Pos)//擺放函數(遞歸調用)(剩餘環數.當前位置)

t{

ttif (Search (Pos)) {//如果當前位置無物體

tttInstantiate(Zero_OBJ,Pos,Quaternion.identity);//創建物體

tttHexagon_List.Add (Pos);//記錄位置

tttif (n > 0) {//如果環大於0繼續遞歸調用

ttttfor(int i=0;i<6;i++){//向周圍探測

tttttPlacing(n-1,new Vector3(Mathf.Sin(60 * i * Mathf.PI / 180) , 0f , Mathf.Cos(60 * i * Mathf.PI / 180)) * Radius + Pos);//探測(環數-1,周圍新位置)

tttt}

ttt}

tt}

t}

tbool Search(Vector3 Pos)//檢索函數(無物體返回真,有物體返回假)

t{

tttfor (int i = 0; i < Hexagon_List.Count; i++) {//逐個檢測位置列表

ttttif (Vector3.Distance (Pos, Hexagon_List [i]) < Radius * 0.2f) {//如果距離很小說明有物體

tttttreturn false;//返回假

tttt}

ttt}

tttreturn true;//遍歷完說明位置上無物體返回真

t}

t// Use this for initialization

tvoid Start () {

ttPlacing (RoundMax, transform.position);//第一次調用遞歸(圈數,當前位置)

t}

t// Update is called once per frame

tvoid Update () {

t}

}

理論是沒有問題,可能Unity3D的運行機制的問題。

========Lv9給出的左右梯形循環創建=========

public class PlacingHexagon_Lv9 : MonoBehaviour {

tpublic GameObject Zero_OBJ;//六邊形物體

public int RoundMax = 10;//最大環數變數

public float Radius = 1f;//六邊形最短寬度

// Use this for initialization

tvoid Start () {

tt//循環列創建

ttfor (int dx = 0; dx <= RoundMax; dx++) {

ttt//向右創建一個高RoundMax的梯形。

ttt//循環列上每個物體(「最下方行」到 「最上方行-列」 循環)每列少一個。

tttfor (int dy = -RoundMax; dy <= RoundMax - dx; dy++) {

tttt//擺放位置=橫向偏移(外切圓半徑與內切圓半徑比為1.732)的一半,0,縱向向上偏移半個

ttttVector3 Pos = new Vector3 (dx*Mathf.Sqrt(3)*0.5f, 0, dy + dx * 0.5f)*Radius;

ttttInstantiate (Zero_OBJ, transform.position + Pos,tQuaternion.identity);

tttt//如果不在中心列上,鏡像創建左側

ttttif(dx!=0){

tttttInstantiate (Zero_OBJ, transform.position + new Vector3(-Pos.x,Pos.y,Pos.z),tQuaternion.identity);

tttt}

ttt}

tt}

t}

t// Update is called once per frame

tvoid Update () {

t}

}


推薦閱讀:

從零開始學基於ARKit的Unity3d遊戲開發系列11
Unity 內存優化 和 內存池使用實踐
Unity3D熱更新LuaFramework入門實戰(2)——資源熱更新
【補遺】基於體積的大氣散射Shader

TAG:Unity游戏引擎 |