Va chạm dựa trên bốn cây / lưới - đưa logic vào hoạt động


13

Trước hết, tôi chỉ viết logic trò chơi của riêng mình trong một thời gian ngắn, vì vậy tôi xin lỗi nếu điều này có vẻ thẳng tiến.

Tôi đã đọc rất nhiều về cây bốn lá và phát hiện va chạm dựa trên lưới. Tôi hiểu logic - về cơ bản không kiểm tra va chạm trừ khi các vật thể ở gần về cơ bản. Nhưng nó không bao giờ được đề cập làm thế nào thực sự thực hiện điều này.

Tôi có một vài phương pháp sở hữu trong đầu nhưng không chắc phương pháp nào là tốt nhất

Kiểm tra va chạm chung - không tối ưu hóa

for(var i:int = 0; i < objects.length; i++){
        //find object A
        var objectA = objects[i];

        for(var j:int = i + 1; j < objects.length; j++){
            //find object B
            var objectB = objects[j];

            if(objectA.collidesWith(objectB){

               //handle collision logic
              }
        }

lưu trữ hàng xóm (phương pháp 1) Nhưng nếu chúng ta muốn tối ưu hóa các va chạm để chỉ kiểm tra các đối tượng ở gần. Chúng ta vẫn chạy qua tất cả các đối tượng hay chúng ta tạo một mảng với các đối tượng gần để kiểm tra?

var objects:Array = new Array();
    var neighbours:Array = new Array();

    for(var i:int = 0; i < objects.length; i++){
        //find object A
        var objectA = objects[i];

        for(var j:int = i + 1; j < objects.length; j++){
            //find object B
            var objectB = objects[j];

            if(objectA.isNear(objectB){

               neighbours.push(objectA, objectB);
              }
        }

    }

    //somewhere else
    for(i:int = 0; i < neighbours.length; i++){
        //only check neighbours

        for(j:int = i + 1; j < neighbours.length; j++){

            if(objectA.collidesWith(objectB){

               //handle collision logic
              }
        }
    }

lặp tất cả các đối tượng nhưng chỉ kiểm tra hàng xóm về va chạm (phương pháp 3) Khả năng khác là chúng ta vẫn lặp qua mọi thứ nhưng kiểm tra xem các đối tượng có ở gần trước khi kiểm tra va chạm không.

for(var i:int = 0; i < objects.length; i++){
        //find object A
        var objectA = objects[i];

        for(var j:int = i + 1; j < objects.length; j++){
            //find object B
            var objectB = objects[j];

            if(objectA.isNear(objectB){
               //they are near - check collision!
               if(objectA.collidesWith(objectB){

               //handle collision logic
              }
            }
        }

    }

Lưu trữ các đối tượng trong dữ liệu gạch (phương pháp 3) Sử dụng sytem dựa trên gạch cho phép tùy chọn khác; Lưu trữ các đối tượng trên một ô cụ thể trong chính dữ liệu của ô đó. Kiểm tra xem đối tượng nào là ô xung quanh có chứa bất kỳ đối tượng nào có thể va chạm với:

var ObjectA;

for(var i:int = 0; i < 4; i ++){
//check 4 surrounding tiles from object A

   if(Object.currentTile + surroundingTile[i] CONTAINS collidable object){
   //check collision!
    if(objectA.collidesWith(surroundingTile.object){

    //handle collision logic
     }

}
}

Tôi luôn cố gắng nhìn vào thế giới thực như một ví dụ. Nếu tôi muốn so sánh các mục với cùng một màu, có vẻ không hợp lý để kiểm tra tất cả các mục ngay cả khi chúng không khớp màu (Phương pháp 2, kiểm tra từng mục). Tôi có thể sẽ thu thập các mục có cùng màu (các đối tượng ở gần nhau) và kiểm tra các mục đó (phương pháp 1), thay vì kiểm tra mọi thứ.

Đây không phải là một so sánh thích hợp vì các mục trong kiểm tra va chạm liên tục di chuyển để trật tự bị xáo trộn. Đó là những gì làm tôi bối rối.

Sẽ hiệu quả hơn nếu kiểm tra từng mục, do đó loại bỏ sự căng thẳng của việc tạo ra một loạt các hàng xóm.

Hoặc là hiệu quả hơn để tìm hàng xóm do đó không phải vòng qua quá nhiều đối tượng để kiểm tra va chạm?

Tiếp tục thay đổi dữ liệu trên mỗi ô có vẻ rất chuyên sâu, vì vậy tôi không chắc đó có phải là ý hay không ..

Tôi đã nghĩ về một trò chơi phòng thủ tháp trong đó tòa tháp cần phát hiện các vật thể nếu các vật thể nằm trong phạm vi trước khi nó bắn vào nó. Và có vẻ như thật ngớ ngẩn khi kiểm tra tất cả các mặt hàng trong khi đôi khi sẽ không có bất kỳ vật thể nào ở gần.

Tôi xin lỗi vì bài viết dài, luôn gặp khó khăn để giải thích chính mình!


đây là ngôn ngữ gì Javascript?
Kyle C

2
Hành động 3, nhưng ngôn ngữ là không liên quan. Chỉ muốn tìm ra cách tốt nhất để xử lý và cấu trúc này :)
omgnoseat 28/03

Câu trả lời:


8

Bạn cần giảm số lần kiểm tra va chạm thực tế. Vâng rõ ràng tôi biết. Vì vậy, hãy giải thích về điều này:

Thuật toán kiểm tra va chạm đầu tiên của bạn mà không có bất kỳ tối ưu hóa nào: nó sẽ thực hiện bao nhiêu kiểm tra trong một lần chạy? Nếu n là số lượng đối tượng, thì đây sẽ là khoảng kiểm tra n * (n-1). Đối với nhiều đối tượng (> 100), điều này sẽ chậm kinh khủng.

Phương pháp kiểm tra hàng xóm của bạn sẽ không nhanh hơn nhiều. Nếu các đối tượng của bạn không tĩnh và di chuyển nhiều, bạn sẽ cần xây dựng danh sách hàng xóm này cho từng đối tượng mọi lúc trong vòng lặp trò chơi của mình. Điều này thực sự tồi tệ hơn thuật toán đầu tiên vì bạn đang thực hiện n * (n-1) để xây dựng danh sách hàng xóm và sau đó kiểm tra từng đối tượng nếu nó va chạm với một trong những hàng xóm của nó.

Bạn cần phân vùng không gian trò chơi của bạn. Hãy nói rằng không gian trò chơi của bạn rộng 400x400 pixel. Bạn có thể phân vùng này thành 4 không gian con mỗi kích thước 200x200 và kiểm tra từng đối tượng mà không gian con thuộc về nó (một đối tượng có thể ở bên trong nhiều không gian con). Sau đó, bạn sẽ chỉ cần kiểm tra xem các đối tượng trong mỗi không gian con có va chạm với các đối tượng khác trong cùng một không gian con hay không.

Vì vậy, chi phí thời gian chạy sẽ là: n để xây dựng danh sách 4 không gian con + (n / 4) * ((n-1) / 4) tốt hơn rất nhiều so với chi phí thời gian chạy trước đó. Điều này có thể được cắt giảm hơn nữa bằng cách làm cho các không gian con nhỏ hơn (ví dụ 50x50).

Vì vậy, thuật toán của chúng tôi bây giờ trông giống như thế này:

for each (object in objects)
  check into which subspace the object belongs

for each (subspace in subspaces)
  for each (object in subspace)
    check object for collision with other objects in same subspace

Điều này là hơi giống với ý tưởng dữ liệu gạch của bạn. Nhưng các không gian con không cần phải có cùng kích thước với gạch.

Chúng ta có thể thực hiện một bước cuối cùng để tối ưu hóa điều này hơn nữa bằng cách sử dụng một phần tư. Gọi k là số không gian con. Để xây dựng danh sách đối tượng không gian, chúng tôi đang thực hiện kiểm tra k * n, dẫn đến rất nhiều kiểm tra nếu thế giới trò chơi của bạn trở nên rộng lớn.

Để giảm chi phí này, chúng tôi sử dụng một phần tư. Một quadtree là một cách khác để phân vùng không gian trò chơi của chúng tôi. Thay vì chia không gian 400x400 của chúng tôi thành 64 không gian con 50x50 và kiểm tra từng đối tượng trong đó có 64 không gian con hiện tại, không gian trò chơi được chia thành 4 không gian con bằng một nửa không gian trò chơi (200x200), lần lượt được chia thành không gian con nhỏ hơn (100x100), lần lượt được chia lại thành không gian con 50x50. Đây là tứ giác của chúng tôi.

Bây giờ nếu chúng ta muốn biết không gian con 50x50 mà một đối tượng thuộc về chúng ta, hãy kiểm tra xem không gian con 200x200 của nó thuộc về không gian con nào. Sau đó, chúng tôi đi sâu hơn một cấp trong nhóm mười bốn của chúng tôi và kiểm tra 4 không gian con 100x100 nằm trong không gian con 200x200 mà chúng tôi vừa tìm thấy. Điều này được lặp lại cho đến khi chúng ta biết không gian con 50x50 mà đối tượng thuộc về. Vì vậy, bao nhiêu kiểm tra là cần thiết bây giờ? 4 cho mỗi cấp độ của góc phần tư (Hãy nhớ một đối tượng có thể nằm ở cạnh của hai không gian con). Vì vậy, chúng ta cần kiểm tra 4 * 3 để gán một đối tượng cho không gian con 50x50 chính xác. Tốt hơn rất nhiều so với 64 kiểm tra.

Vì vậy, thuật toán tứ giác của chúng tôi cần kiểm tra 4 * 3 * n để xây dựng danh sách không gian con và sau đó kiểm tra k * (n / k) để kiểm tra va chạm của từng đối tượng.


Đó là một awnser rất rõ ràng và dễ hiểu, cảm ơn rất nhiều! Làm thế nào nó được xử lý trên không gian con một đối tượng là gì? Là không gian con được xử lý như một đối tượng, trong đó các đối tượng trên nó được lưu dưới dạng các mảng và được kiểm tra đối với nhau? Hay bạn chỉ kiểm tra xem đó là không gian con nào bằng cách kiểm tra X và Y bên trong vòng lặp chính? Có vẻ như việc xây dựng và thay đổi mảng mọi lúc là không hiệu quả. Vì vậy, tôi muốn chắc chắn rằng tôi sử dụng phương pháp thích hợp :) Tôi cũng có thể thấy một vấn đề xảy ra khi các đối tượng có kích thước khác nhau. Tôi đoán không gian con nhỏ nhất sẽ lớn bằng đối tượng lớn nhất?
omgnoseat

Tôi rất vui khi được giúp đỡ :) Một không gian con sẽ là một đối tượng duy trì 4 không gian con mà nó chứa. Không gian con nhỏ nhất là khác nhau vì nó không chứa các không gian con nữa, mà là một danh sách các đối tượng của bạn. Xem xét chi phí cập nhật: cây không gian con được xây dựng một lần khi bắt đầu trò chơi. Trong mỗi vòng lặp của vòng lặp chính, các đối tượng liệt kê trong các không gian con nhỏ nhất sẽ bị xóa và điền lại. Vì vậy, chỉ có danh sách thêm / loại bỏ là cần thiết. Không có mảng cần phải thay đổi. Không gian con nhỏ nhất phải đủ lớn để chứa một số đối tượng trò chơi. Làm thế nào lớn phụ thuộc vào trò chơi của bạn và có thể được điều chỉnh sau này.
Stephen

Cảm ơn, quên rằng chúng ta cũng sẽ kiểm tra va chạm giữa các đối tượng thực tế trong không gian con nhỏ nhất, có nghĩa là nó sẽ có thể giữ nhiều đối tượng ngay bây giờ. Tôi đã bắt đầu thử nghiệm và nó rất tuyệt. Rắc rối lớn nhất mà tôi gặp phải là phát hiện không gian con thuộc đối tượng nào. Tôi tiếp tục lặp qua các không gian con các giá trị X và Y, đây có phải là một phương thức thích hợp không?
omgnoseat

Làm thế nào để bạn xử lý các đối tượng mở rộng vào nhiều hơn một không gian con (tức là vị trí của chúng nằm trên hoặc gần một ranh giới)?
mghicks

Đơn giản: Tôi không. Các đối tượng có thể là một phần của nhiều không gian con, nếu chúng nằm trên ranh giới của mỗi không gian con. Vì vậy, một đối tượng có thể là một phần của tối đa 4 không gian con. Nhưng đây là thiểu số.
Stephen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.