2011-09-06 29 views
9

Tôi đang cố gắng tạo một tập hợp các điểm (được biểu diễn bằng cấu trúc Vector) gần như mô hình một thiên hà xoắn ốc.Thuật toán thế hệ Galaxy

Mã C# tôi đã chơi với bên dưới; nhưng tôi chỉ có thể làm cho nó tạo ra một 'cánh tay' duy nhất của thiên hà.

public Vector3[] GenerateArm(int numOfStars, int numOfArms, float rotation) 
    { 
     Vector3[] result = new Vector3[numOfStars]; 
     Random r = new Random(); 

     float fArmAngle = (float)((360/numOfArms) % 360); 
     float fAngularSpread = 180/(numOfArms * 2); 

     for (int i = 0; i < numOfStars; i++) 
     { 

      float fR = (float)r.NextDouble() * 64.0f; 
      float fQ = ((float)r.NextDouble() * fAngularSpread) * 1; 
      float fK = 1; 

      float fA = ((float)r.NextDouble() % numOfArms) * fArmAngle; 


      float fX = fR * (float)Math.Cos((MathHelper.DegreesToRadians(fA + fR * fK + fQ))); 
      float fY = fR * (float)Math.Sin((MathHelper.DegreesToRadians(fA + fR * fK + fQ))); 

      float resultX = (float)(fX * Math.Cos(rotation) - fY * Math.Sin(rotation)); 
      float resultY = (float)(fY * Math.Cos(rotation) - fX * Math.Sin(rotation)); 

      result[i] = new Vector3(resultX, resultY, 1.0f); 
     } 

     return result; 
    } 
+0

Hình như bạn cần một vòng lặp thứ hai dựa trên numOfArms và offseting góc cánh tay bởi khoảng cách góc giữa cánh tay. Sau đó thay đổi vòng lặp lặp bên trong của bạn thành numOfStars/numOfArms. –

+0

Điều này không thuộc về gamedev? –

+0

Ngoài ra: http://stackoverflow.com/questions/348321/mathematical-question-procedural-generation-of-a-galaxy –

Trả lời

2

tôi sẽ trừu tượng có chức năng ra thành một chức năng createArm.

Sau đó, bạn có thể lưu trữ mỗi cánh tay làm thiên hà của chính nó (tạm thời).

Vì vậy, nếu bạn muốn 2 tay, hãy làm 2 thiên hà 5000. Sau đó, xoay một trong số chúng 0 độ quanh gốc (do đó không di chuyển) và 180 độ khác xung quanh gốc.

Với điều này, bạn có thể thực hiện một số lượng tùy ý vũ khí bằng cách sử dụng số lượng xoay khác nhau. Bạn thậm chí có thể thêm một số "nhập tịch" vào nó bằng cách làm cho khoảng cách quay ngẫu nhiên hơn, giống như với một phạm vi thay vì thẳng (360/n). Ví dụ, 5 vũ khí sẽ là 0, 72, 144, 216, 288. Tuy nhiên, với một số ngẫu nhiên bạn có thể làm cho nó 0, 70, 146, 225, 301.

Edit:

Một số nhanh chóng google-fu cho tôi biết (source)

q = initial angle, f = angle of rotation. 

x = r cos q 
y = r sin q 

x' = r cos (q + f) = r cos q cos f - r sin q sin f 
y' = r sin (q + w) = r sin q cos f + r cos q sin f 

hence: 
x' = x cos f - y sin f 
y' = y cos f + x sin f 
+0

Bất kỳ ý tưởng làm thế nào tôi có thể đi về việc thay đổi thuật toán để 'xoay' tất cả các giá trị xung quanh 0,0? Tôi có thể làm điều đó với ma trận xoay trên mỗi điểm, nhưng sẽ tốt hơn nếu có thể truyền giá trị 'xoay vòng' vào hàm createArm và có các điểm được xoay vòng trên thế hệ. –

+0

có bất kỳ thiên hà xoắn ốc nào với một số cánh tay không phải là hai không? tôi không nghĩ rằng nó xảy ra trừ khi có lẽ đó là một tính năng thoáng qua do sự gián đoạn trong một số cách (sáp nhập/va chạm). –

+0

@ Chris Tôi thêm một số công thức không biết xấu hổ tách từ siggraph. – corsiKa

4

Kiểm tra điều này. Đó là một mô phỏng của thiên hà sử dụng lý thuyết sóng mật độ. Mã có sẵn. http://beltoforion.de/galaxy/galaxy_en.html

+0

liên kết đã chết, nhưng đối với tất cả những người vẫn muốn đọc nó, hãy sử dụng liên kết sau https://web.archive.org/web/20140119101505/http://beltoforion.de/galaxy/galaxy_en.html – Peter

4

Tôi thích ý tưởng này rất nhiều, tôi đã phải chơi với nó một mình và đây là kết quả của tôi. Lưu ý rằng tôi đã sử dụng PointF thay vì Vector3, nhưng bạn sẽ có thể tìm kiếm và thay thế và thêm , 0) ở một vài nơi.

PointF[] points; 

private void Render(Graphics g, int width, int height) 
{ 
    using (Brush brush = new SolidBrush(Color.FromArgb(20, 150, 200, 255))) 
    { 
     g.Clear(Color.Black); 
     foreach (PointF point in points) 
     { 
      Point screenPoint = new Point((int)(point.X * (float)width), (int)(point.Y * (float)height)); 
      screenPoint.Offset(new Point(-2, -2)); 
      g.FillRectangle(brush, new Rectangle(screenPoint, new Size(4, 4))); 
     } 
     g.Flush(); 
    } 
} 

public PointF[] GenerateGalaxy(int numOfStars, int numOfArms, float spin, double armSpread, double starsAtCenterRatio) 
{ 
    List<PointF> result = new List<PointF>(numOfStars); 
    for (int i = 0; i < numOfArms; i++) 
    { 
     result.AddRange(GenerateArm(numOfStars/numOfArms, (float)i/(float)numOfArms, spin, armSpread, starsAtCenterRatio)); 
    } 
    return result.ToArray(); 
} 

public PointF[] GenerateArm(int numOfStars, float rotation, float spin, double armSpread, double starsAtCenterRatio) 
{ 
    PointF[] result = new PointF[numOfStars]; 
    Random r = new Random(); 

    for (int i = 0; i < numOfStars; i++) 
    { 
     double part = (double)i/(double)numOfStars; 
     part = Math.Pow(part, starsAtCenterRatio); 

     float distanceFromCenter = (float)part; 
     double position = (part * spin + rotation) * Math.PI * 2; 

     double xFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread; 
     double yFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread; 

     float resultX = (float)Math.Cos(position) * distanceFromCenter/2 + 0.5f + (float)xFluctuation; 
     float resultY = (float)Math.Sin(position) * distanceFromCenter/2 + 0.5f + (float)yFluctuation; 

     result[i] = new PointF(resultX, resultY); 
    } 

    return result; 
} 

public static double Pow3Constrained(double x) 
{ 
    double value = Math.Pow(x - 0.5, 3) * 4 + 0.5d; 
    return Math.Max(Math.Min(1, value), 0); 
} 

Ví dụ:

points = GenerateGalaxy(80000, 2, 3f, 0.1d, 3); 

Kết quả: Galaxy