Tôi đã có một loạt các vật thể có kích thước và vận tốc khác nhau hấp dẫn về phía nhau. Trên mỗi bản cập nhật, tôi phải đi qua mọi đối tượng và cộng các lực do trọng lực của mọi đối tượng khác. Nó không có quy mô rất tốt, là một trong hai nút thắt lớn mà tôi đã tìm thấy trong trò chơi của mình và tôi không biết phải làm gì để cải thiện hiệu suất.
Nó cảm thấy như tôi sẽ có thể cải thiện hiệu suất. Tại bất kỳ thời điểm nào, có thể 99% các đối tượng trong hệ thống sẽ chỉ có ảnh hưởng không đáng kể đến một đối tượng. Tất nhiên tôi không thể sắp xếp các vật thể theo khối lượng và chỉ xem xét 10 vật thể lớn nhất hoặc thứ gì đó, bởi vì lực thay đổi theo khoảng cách nhiều hơn so với khối lượng (phương trình nằm dọc theo đường thẳng force = mass1 * mass2 / distance^2
). Tôi nghĩ rằng một sự gần đúng tốt sẽ là xem xét các vật thể lớn nhất và các vật thể gần nhất, bỏ qua hàng trăm mảnh đá nhỏ ở phía bên kia của thế giới không thể ảnh hưởng đến bất cứ điều gì - nhưng để tìm ra những vật thể nào gần nhất tôi phải lặp đi lặp lại trên tất cả các đối tượng và vị trí của chúng thay đổi liên tụcVì vậy, nó không giống như tôi chỉ có thể làm một lần.
Hiện tại tôi đang làm một cái gì đó như thế này:
private void UpdateBodies(List<GravitatingObject> bodies, GameTime gameTime)
{
for (int i = 0; i < bodies.Count; i++)
{
bodies[i].Update(i);
}
}
//...
public virtual void Update(int systemIndex)
{
for (int i = systemIndex + 1; i < system.MassiveBodies.Count; i++)
{
GravitatingObject body = system.MassiveBodies[i];
Vector2 force = Gravity.ForceUnderGravity(body, this);
ForceOfGravity += force;
body.ForceOfGravity += -force;
}
Vector2 acceleration = Motion.Acceleration(ForceOfGravity, Mass);
ForceOfGravity = Vector2.Zero;
Velocity += Motion.Velocity(acceleration, elapsedTime);
Position += Motion.Position(Velocity, elapsedTime);
}
(lưu ý rằng tôi đã xóa rất nhiều mã - ví dụ: các thử nghiệm va chạm, tôi không lặp lại các đối tượng lần thứ hai để phát hiện va chạm).
Vì vậy, tôi không phải lúc nào cũng lặp đi lặp lại trong toàn bộ danh sách - Tôi chỉ làm điều đó cho đối tượng đầu tiên và mỗi khi đối tượng tìm thấy lực mà nó cảm thấy đối với một đối tượng khác, thì đối tượng khác lại cảm thấy cùng một lực, vì vậy nó chỉ cập nhật cả hai chúng - và sau đó đối tượng đầu tiên đó không phải được xem xét lại cho phần còn lại của bản cập nhật.
Các hàm Gravity.ForceUnderGravity(...)
và Motion.Velocity(...)
, v.v. chỉ sử dụng một chút toán học vectơ tích hợp của XNA.
Khi hai vật thể va chạm, chúng tạo ra các mảnh vỡ không khối lượng. Nó được giữ trong một danh sách riêng biệt và các vật thể lớn không lặp đi lặp lại trên các mảnh vỡ như là một phần của tính toán vận tốc của chúng, nhưng mỗi mảnh vỡ phải lặp đi lặp lại trên các hạt lớn.
Điều này không phải mở rộng đến giới hạn đáng kinh ngạc. Thế giới không giới hạn, nó chứa một đường viền phá hủy các vật thể đi ngang qua nó - tôi muốn có thể xử lý khoảng một nghìn vật thể, hiện tại trò chơi bắt đầu nghẹt thở khoảng 200.
Bất kỳ suy nghĩ về cách tôi có thể cải thiện điều này? Một số heuristic tôi có thể sử dụng để cạo chiều dài vòng lặp từ hàng trăm xuống chỉ một vài? Một số mã tôi có thể thực thi ít thường xuyên hơn mọi bản cập nhật? Tôi có nên đa luồng cho đến khi nó đủ nhanh để cho phép một thế giới có kích thước phù hợp? Tôi có nên cố gắng giảm tải các tính toán vận tốc cho GPU không? Nếu vậy, làm thế nào tôi kiến trúc sư? Tôi có thể giữ dữ liệu tĩnh, chia sẻ trên GPU không? Tôi có thể tạo các chức năng HLSL trên GPU và gọi chúng một cách tùy tiện (sử dụng XNA) hay chúng có phải là một phần của quy trình vẽ không?
G * m1 * m2 / r^2
, trong đó G chỉ là để điều chỉnh hành vi. (mặc dù tôi không thể có chúng theo một con đường, bởi vì người dùng có thể làm phiền hệ thống)