Hiệu quả phát hiện va chạm dựa trên Ngói cho rất nhiều hình vuông?


9

Hiện tại tôi đang tự mình làm một trò chơi dựa trên gạch (nghĩ Terraria, nhưng ít tưởng tượng hơn (tôi nghĩ đó là một từ? Xin lỗi nếu không phải vậy)).

Dù sao, tôi hiện đang làm việc phát hiện va chạm (đối với các trường hợp góc!) Đó là một bước tiến lớn đối với tôi. Có một cái gì đó cực kỳ hài lòng về việc nhìn thấy một sprite không chạy qua một khối. Nhưng sau đó tôi đã có ý tưởng để điểm chuẩn. Ý kiến ​​tồi.

1.000 hình vuông, không có vấn đề. 10.000 ô vuông, cho 3 ký tự là loại lag. 100.000 ô vuông (bản đồ thực sự rất lớn), cho 3 nhân vật là không thể chơi được.

Tôi gặp vấn đề khi tôi thậm chí không muốn xem xét các khối quá xa người chơi, nhân vật, vật phẩm, v.v., nhưng tôi không muốn tải những thứ đó ra khỏi bộ nhớ liên tục.

Đây là thuật toán của tôi cho đến nay, xin vui lòng chỉ trích.

foreach (Block in level)
{
    if (distance from block to player > a specified amount)
        ignore this block;
    else
    {
        get the intersection depth between the two bounding boxes
        if (depth of intersection != Zero-vector)
        {
            check y size vs x size
            resolve on smallest axis
        }
    }
}

Như bạn sẽ lưu ý, khi kích thước cấp độ lớn hơn, Thứ tự của thuật toán này sẽ tăng theo khối N. Tôi thậm chí không muốn xem xét các khối thậm chí không ở gần trình phát.

Tôi nghĩ có thể sử dụng một mảng kép (0,0) đến (mapWidth, mapHeight) thay vì danh sách, tính toán vùng nguy hiểm tùy thuộc vào vị trí của người đó, ví dụ: nếu vị trí của người chơi ở (10, 20) nó sẽ nhìn từ (0, 10) đến (20, 30), v.v.

Bất kỳ suy nghĩ và cân nhắc là tuyệt vời, cảm ơn bạn.


1
Và chào mừng đến với stackexchange! :-) Đừng quên đọc FAQ nếu bạn không biết toàn bộ hệ thống QA và danh tiếng hoạt động như thế nào.
David Gouveia

Chắc chắn những viên gạch này lớn hơn 16 x 16 pixel, ở mức 1920 x 1080 là 8.100 viên. Chắc chắn bạn biết các thực thể có thể di chuyển được ở đâu và bạn chỉ có thể kiểm tra các ô trên lưới có thể nằm trong phạm vi (nếu một trong 160 * 160 và trung tâm nằm trong ô (12,12) bạn chỉ cần kiểm tra giữa các ô (6 , 6) và (18,18) cho tổng số ~ 150 gạch có thể.). Chắc chắn gạch dưới trọng lực chỉ rơi xuống, và vì vậy bạn chỉ cần tìm gạch tiếp theo bên dưới nó.
DampeS8N

Bạn có nghĩ rằng 16x16 là quá nhỏ? Tôi sẽ không khó để thay đổi kích thước của gạch, vì bất cứ điều gì tham chiếu đến chiều cao / chiều cao là một hằng số tĩnh. Tất cả những gì tôi phải làm là phóng to chúng trong Paint.NET, điều này thật tuyệt vì nó bổ sung thêm chi tiết.
Ross

Bạn có muốn chia sẻ mã va chạm của bạn? : /
tro999

Câu trả lời:


7

Vâng, bạn đang suy nghĩ chính xác. Bạn nên sử dụng một mảng 2D của gạch vì điều đó cho phép bạn lập chỉ mục các ô theo vị trí.

Block[,] level = new Block[width, height];

Và vì người chơi chỉ có thể va chạm với các ô xung quanh của nó, nên số lần kiểm tra va chạm bạn cần làm là rất ít. Điều này tất nhiên phụ thuộc vào kích thước của người chơi. Mẫu Platformer thực hiện như thế này:

int leftTile = (int)Math.Floor((float)characterBounds.Left / tileWidth);
int rightTile = (int)Math.Ceiling(((float)characterBounds.Right / tileWidth)) - 1;
int topTile = (int)Math.Floor((float)characterBounds.Top / tileHeight);
int bottomTile = (int)Math.Ceiling(((float)characterBounds.Bottom / tileHeight)) - 1;

for (int y = topTile; y <= bottomTile; ++y)
{
    for (int x = leftTile; x <= rightTile; ++x)
    {
        // Handle collisions with the tile level[x,y] just like you were doing!
    }
}

Kiểm tra mẫu nếu bạn vẫn có bất kỳ vấn đề.


Đây là một thuật toán nhỏ rất hay, tôi thậm chí chưa từng nghe về mẫu Platformer (tôi nên có, nhưng tôi khẳng định không biết gì). Cảm ơn bạn!
Ross

@Ross Thật sao? Bạn sẽ ngạc nhiên khi thấy giải pháp của bạn giống với mẫu như thế nào. :-) Trừ phần danh sách, mọi thứ khác giống hệt nhau (các ô giới hạn giao nhau, lấy độ sâu giao cắt, giải quyết trên trục nhỏ nhất).
David Gouveia

1
Người đàn ông, tôi chỉ nhìn vào nó. >. <Ước gì tôi biết điều này 2 ngày trước !! Chà, tôi mới làm quen với XNA nhưng tôi đã mê mẩn đồ họa 2D (chỉ là OpenGL, không có nhiều lập trình trò chơi). Tôi đoán tôi nên kiểm tra thêm tài nguyên trước khi tôi đi đầu vào mã hóa.
Ross

1

Tôi đoán câu trả lời của tôi sẽ là câu trả lời của bạn! ;-)

Nếu bạn có vị trí người chơi (và kích thước), bạn có thể tính toán các chỉ số của các ô xung quanh (là các ô duy nhất được kiểm tra chi tiết). Bằng cách này, nó không liên quan đến bản đồ của bạn lớn như thế nào, nó chỉ phụ thuộc vào kích thước thực tế của người chơi của bạn do đó dẫn đến nhiều ô tiềm năng hơn để kiểm tra.

Có thể kiểm tra hướng dẫn về va chạm tại riemers.net nếu bạn chưa có.


Tôi đã nghe nói về Riemer nhưng chưa bao giờ tìm kiếm, cảm ơn!
Ross

1

Khi xử lý một số lượng lớn các va chạm, bạn thường muốn áp dụng một cấu trúc nâng cao hơn , chẳng hạn như Quadtree hoặc Hashmap để kiểm tra các va chạm đó.

Vì gạch là tĩnh, tôi sẽ đề nghị sử dụng Quadtree. Một cây quad được tạo thành từ quads. Mỗi hình tứ giác được tạo thành từ bốn hình chữ nhật và mỗi hình chữ nhật đó là hình tứ giác. Điều này tiếp tục đệ quy lên đến một kích thước được chỉ định. Mỗi ô có thể chứa một danh sách các ô nằm trong khu vực đó của màn hình. Bằng cách đó, khi bạn kiểm tra va chạm, bạn có thể

  1. Hạn chế kiểm tra đối với những người trong vùng lân cận
  2. Hạn chế kiểm tra chỉ các đối tượng đang di chuyển

Bây giờ nếu bạn thậm chí không muốn nhìn vào gạch khỏi màn hình thì bạn có thể làm một cái gì đó như

public bool CheckCollision(myPosition) {
    if(quadNodes.Count > 0) {
        // This is not a leaf, keep checking
        foreach(Quad node in quadNodes) {
            if(node.Position is insideViewport && nearPlayer)
                // Continue recursion
            }
        }
    }
    else {
        // This is a leaf, do checks
        foreach(Tile tile in tileList) {
            if(collision)
                return true;
        }
        return false;
    }
}

Hmm, tôi đã nghe nói về Octrees trong phát hiện va chạm 3D nhưng chưa bao giờ thấy Cấu trúc dữ liệu nâng cao được sử dụng để phát hiện va chạm 2D. Cảm ơn rât nhiều!
Ross

1
Vì trò chơi của anh ấy (giả sử Terraria) được tạo thành từ các ô cách đều nhau, sử dụng lưới sẽ dễ dàng hơn và nhanh hơn rất nhiều so với một phần tư. Một tứ giác hoạt động tốt hơn cho các thế giới phức tạp hơn, nơi lưới sẽ khó phù hợp và mọi thứ đều có kích thước tùy ý.
David Gouveia

1
Bạn đúng nếu đó là một trò chơi hoàn toàn dựa trên lưới, thậm chí xuống kích cỡ nhân vật. Tôi biết rằng ở Terraria họ cũng có những con quái vật không phù hợp với định dạng lưới. Tôi đã chạy theo giả định rằng thế giới cơ bản được làm bằng gạch nhưng các vật thể khác sẽ khác và họ có thể lưu trữ chúng trong một cấu trúc tương tự để tránh xây dựng một thế giới khác. Tôi cho rằng họ có thể sử dụng lưới cho gạch sau đó một cấu trúc khác (nếu cần) cho các đối tượng tùy ý khác.
Mike Cluck

1
Đó là những gì tôi sắp đề xuất :) Lưới nên được sử dụng để xử lý các va chạm với địa hình, trong khi một góc phần tư có thể được sử dụng để xử lý các va chạm giữa các đối tượng.
David Gouveia

Thật. Ngay bây giờ mỗi hộp giới hạn có 2 ^ kích thước nguồn. Điều này làm cho nó dễ dàng hơn nhiều để tôi phát hiện va chạm. Một lưới sẽ phù hợp với nhu cầu của tôi bây giờ.
Ross
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.