Tôi đang thực hiện một trò chơi khám phá không gian, nó sẽ có nhiều hành tinh và các vật thể khác đều có lực hấp dẫn thực tế. Tôi hiện đang có một hệ thống hoạt động, nhưng nếu số lượng hành tinh vượt quá 70, FPS sẽ giảm tốc độ theo cấp số nhân thực tế. Tôi đang làm nó trong C # và XNA.
Tôi đoán là tôi sẽ có thể thực hiện các phép tính trọng lực giữa 100 vật thể mà không cần loại căng thẳng này, vì vậy rõ ràng phương pháp của tôi không hiệu quả như mong muốn.
Tôi có hai tệp, Gravity.cs và EntityEngine.cs. Gravity quản lý CHỈ các phép tính trọng lực, EntityEngine tạo ra một thể hiện của Gravity và chạy nó, cùng với các phương thức liên quan đến thực thể khác.
EntityEngine.cs
public void Update()
{
foreach (KeyValuePair<string, Entity> e in Entities)
{
e.Value.Update();
}
gravity.Update();
}
.
Trọng lực.cs
namespace ExplorationEngine
{
public class Gravity
{
private EntityEngine entityEngine;
private Vector2 Force;
private Vector2 VecForce;
private float distance;
private float mult;
public Gravity(EntityEngine e)
{
entityEngine = e;
}
public void Update()
{
//First loop
foreach (KeyValuePair<string, Entity> e in entityEngine.Entities)
{
//Reset the force vector
Force = new Vector2();
//Second loop
foreach (KeyValuePair<string, Entity> e2 in entityEngine.Entities)
{
//Make sure the second value is not the current value from the first loop
if (e2.Value != e.Value )
{
//Find the distance between the two objects. Because Fg = G * ((M1 * M2) / r^2), using Vector2.Distance() and then squaring it
//is pointless and inefficient because distance uses a sqrt, squaring the result simple cancels that sqrt.
distance = Vector2.DistanceSquared(e2.Value.Position, e.Value.Position);
//This makes sure that two planets do not attract eachother if they are touching, completely unnecessary when I add collision,
//For now it just makes it so that the planets are not glitchy, performance is not significantly improved by removing this IF
if (Math.Sqrt(distance) > (e.Value.Texture.Width / 2 + e2.Value.Texture.Width / 2))
{
//Calculate the magnitude of Fg (I'm using my own gravitational constant (G) for the sake of time (I know it's 1 at the moment, but I've been changing it)
mult = 1.0f * ((e.Value.Mass * e2.Value.Mass) / distance);
//Calculate the direction of the force, simply subtracting the positions and normalizing works, this fixes diagonal vectors
//from having a larger value, and basically makes VecForce a direction.
VecForce = e2.Value.Position - e.Value.Position;
VecForce.Normalize();
//Add the vector for each planet in the second loop to a force var.
Force = Vector2.Add(Force, VecForce * mult);
//I have tried Force += VecForce * mult, and have not noticed much of an increase in speed.
}
}
}
//Add that force to the first loop's planet's position (later on I'll instead add to acceleration, to account for inertia)
e.Value.Position += Force;
}
}
}
}
Tôi đã sử dụng nhiều mẹo khác nhau (về tối ưu hóa trọng lực, không phân luồng) từ câu hỏi NÀY (mà tôi đã thực hiện ngày hôm qua). Tôi đã tạo ra phương pháp trọng lực này (Gravity.Update) hiệu quả như tôi biết cách tạo ra nó. Thuật toán O (N ^ 2) này dường như vẫn ăn hết năng lượng CPU của tôi.
Đây là một LINK (ổ đĩa google, đi đến Tệp> tải xuống, giữ .Exe với thư mục nội dung, bạn sẽ cần XNA Framework 4.0 Redist. Nếu bạn chưa có nó) cho phiên bản trò chơi hiện tại của tôi. Nhấp chuột trái làm cho một hành tinh, nhấp chuột phải loại bỏ hành tinh cuối cùng. Chuột di chuyển camera, cuộn bánh xe phóng to và thu nhỏ. Xem FPS và Planet Count để biết ý tôi nói về các vấn đề hiệu suất trong 70 hành tinh. (TẤT CẢ 70 hành tinh phải di chuyển, tôi đã có 100 hành tinh đứng yên và chỉ có 5 hành tinh di chuyển trong khi vẫn có 300 khung hình / giây, vấn đề phát sinh khi 70+ đang di chuyển xung quanh)
Sau 70 hành tinh được thực hiện, xe tăng hiệu suất theo cấp số nhân. Với <70 hành tinh, tôi nhận được 330 khung hình / giây (tôi có giới hạn ở mức 300). Ở 90 hành tinh, FPS chỉ còn khoảng 2, nhiều hơn thế và nó dao động ở mức 0 FPS. Thật kỳ lạ, khi tất cả các hành tinh đều đứng yên, FPS tăng trở lại khoảng 300, nhưng ngay khi có thứ gì đó di chuyển, nó quay trở lại với những gì nó đã xảy ra, tôi không có hệ thống nào để thực hiện điều này, nó chỉ xảy ra.
Tôi đã xem xét đa luồng, nhưng câu hỏi trước đó tôi đã hỏi đã dạy cho tôi một hoặc hai điều, và tôi thấy bây giờ đó không phải là một lựa chọn khả thi.
Thay vào đó, tôi cũng nghĩ có lẽ tôi có thể thực hiện các tính toán trên GPU của mình, mặc dù tôi không nghĩ rằng nó là cần thiết. Tôi cũng không biết làm thế nào để làm điều này, nó không phải là một khái niệm đơn giản và tôi muốn tránh nó trừ khi ai đó biết một cách đơn giản thực sự thân thiện để thực hiện nó sẽ làm việc để tính toán trọng lực cơ thể. (Tôi có một NVidia gtx 660)
Cuối cùng tôi đã xem xét sử dụng một hệ thống loại mười bốn. (Mô phỏng Barnes Hut) Tôi đã được nói (trong câu hỏi trước) rằng đây là một phương pháp tốt thường được sử dụng, và nó có vẻ hợp lý và đơn giản, tuy nhiên việc triển khai diễn ra trong đầu tôi và tôi không tìm thấy một cách tốt hướng dẫn cho C # nhưng giải thích nó theo cách tôi có thể hiểu hoặc sử dụng mã mà cuối cùng tôi có thể tìm ra.
Vì vậy, câu hỏi của tôi là: Làm thế nào tôi có thể làm cho phương pháp trọng lực của mình hiệu quả hơn, cho phép tôi sử dụng hơn 100 vật thể (tôi có thể kết xuất 1000 hành tinh với hơn 300 FPS không cần tính toán trọng lực) và nếu tôi không thể làm gì nhiều để cải thiện hiệu suất (bao gồm một số loại hệ thống tứ giác), tôi có thể sử dụng GPU của mình để thực hiện các phép tính không?
List
và Dictionary
(và của nó Keys
và Values
bộ sưu tập). Chúng khá an toàn để sử dụng với foreach
. ( foreach
trong C # không sử dụng IEnumerator
, nó sử dụng kiểu gõ vịt để các điều tra viên có thể struct
và làm việc như mong đợi).
IDisposable
loại giá trị sẽ không có hộp, thay vì chỉ ngụ ý nó.)