Làm thế nào để xử lý phát hiện va chạm hoàn hảo với xoay vòng?


8

Có ai có ý tưởng làm thế nào để đạt được phát hiện va chạm hoàn hảo pixel xoay với Bitmap trong Android không? Hay nói chung cho vấn đề đó? Hiện tại tôi có mảng pixel nhưng tôi không biết cách thao tác chúng dựa trên số độ tùy ý.

Câu trả lời:


11

Tôi không quen thuộc với Android vì vậy tôi không biết bạn có những công cụ nào theo ý của bạn, nhưng tôi có thể cho bạn biết một cách để thực hiện điều này một cách chung chung. Làm thế nào dễ dàng sẽ phụ thuộc vào những gì Android cung cấp cho bạn. Bạn sẽ cần ma trận hoặc ít nhất là chúng sẽ đơn giản hóa các phép tính rất nhiều.

Đối với người mới bắt đầu, hãy kiểm tra va chạm hộp giới hạn và quay lại ngay lập tức nếu họ không va chạm để tránh tính toán thêm. Điều đó hợp lý bởi vì nếu các hộp giới hạn không va chạm thì đảm bảo rằng sẽ không có pixel nào bị va chạm.

Sau đó, nếu cần kiểm tra va chạm hoàn hảo pixel, thì điểm quan trọng nhất là bạn phải thực hiện kiểm tra đó trong cùng một không gian . Điều này có thể được thực hiện bằng cách lấy từng pixel từ sprite A, áp dụng một loạt các phép biến đổi để đưa chúng vào không gian cục bộ của sprite B, sau đó kiểm tra xem nó có va chạm với bất kỳ pixel nào ở vị trí đó trên sprite B. Một sự va chạm xảy ra khi cả hai pixel kiểm tra là mờ đục.

Vì vậy, điều đầu tiên bạn cần là xây dựng một ma trận thế giới cho mỗi sprite. Có thể có các hướng dẫn trực tuyến dạy cho bạn cách tạo một cái, nhưng về cơ bản nó phải là sự kết hợp của một vài ma trận đơn giản hơn theo thứ tự sau:

Translation(-Origin) * Scale * Rotation * Translation(Position)

Tiện ích của ma trận này là bằng cách nhân một điểm trong không gian cục bộ - và ví dụ, nếu bạn nhận được các pixel bằng phương thức như bitmap.getPixelAt(10,20)10,20 được xác định trong không gian cục bộ - bởi ma trận thế giới tương ứng sẽ di chuyển nó vào không gian thế giới:

LocalA * WorldMatrixA -> World
LocalB * WorldMatrixB -> World

Và nếu bạn đảo ngược các ma trận, bạn cũng có thể đi theo hướng ngược lại, tức là biến các điểm từ không gian thế giới thành từng không gian cục bộ của sprite tùy thuộc vào ma trận bạn đã sử dụng:

World * InverseWorldMatrixA -> LocalA
World * InverseWorldMatrixB -> LocalB

Vì vậy, để di chuyển một điểm từ không gian cục bộ của A vào không gian cục bộ của sprite B , trước tiên, bạn phải chuyển đổi nó bằng ma trận thế giới của sprite A, để đưa nó vào không gian thế giới, sau đó sử dụng ma trận thế giới nghịch đảo của B , để đưa nó vào không gian địa phương của sprite B:

LocalA * WorldMatrixA -> World * InverseWorldMatrixB -> LocalB

Sau khi chuyển đổi, bạn kiểm tra xem điểm mới có nằm trong giới hạn của sprite B hay không và nếu có, bạn kiểm tra pixel tại vị trí đó giống như bạn đã làm cho sprite A. Vì vậy, toàn bộ quá trình trở thành như thế này (bằng mã giả và chưa được kiểm tra) :

bool PixelCollision(Sprite a, Sprite B)
{
    // Go over each pixel in A
    for(i=0; i<a.Width; ++i)
    {
        for(j=0; j<a.Height; ++j)
        {
            // Check if pixel is solid in sprite A
            bool solidA = a.getPixelAt(i,j).Alpha > 0;

            // Calculate where that pixel lies within sprite B's bounds
            Vector3 positionB = new Vector3(i,j,0) * a.WorldMatrix * b.InverseWorldMatrix;

            // If it's outside bounds skip to the next pixel
            if(positionB.X<0 || positionB.Y<0 || 
               positionB.X>=b.Width || positionB.Y>=b.Height) continue;

            // Check if pixel is solid in sprite B
            bool solidB = b.getPixelAt(positionB.X, positionB.Y).Alpha > 0;

            // If both are solid then report collision
            if(solidA && solidB) return true;
        }
    }
    return false;
}

1
Tôi thích điều này bởi vì nó thanh lịch, nhưng sử dụng ma trận như thế này - nhân ma trận 3x3 trên mỗi pixel - sẽ đưa ra một số hình phạt hiệu năng khá nghiêm trọng đối với bất kỳ ngoại trừ bitmap nhỏ nhất, đặc biệt là trên hầu hết các thiết bị Android.
3Dave

2
@DavidLively Thật vậy, đây sẽ là một quá trình tốn kém về mặt tính toán. Và tôi nghĩ ngay cả khi các phép tính ma trận không được kiểm soát thành các phép tính thông thường với lượng giác - có thể bỏ qua tỷ lệ nếu nó không được sử dụng - nó vẫn sẽ khá giống nhau. Có thể có những giải pháp khác, nhưng tôi không thể nghĩ ra. Cuối cùng, giải pháp tốt nhất sẽ là suy ngẫm xem liệu phát hiện va chạm hoàn hảo pixel có thực sự cần thiết hay không. Và một số trò chơi sử dụng các va chạm hoàn hảo pixel (như các trò chơi Sonic đầu tiên) đã trừu tượng hóa các nhân vật thành một loạt các điểm va chạm thay thế.
David Gouveia

điểm tốt; Tôi đang vắt óc cố gắng đưa ra một giải pháp thay thế không liên quan đến việc trừ bitmap và tìm kiếm các đỉnh. Có lẽ có một cơ hội cho một bài báo ở đâu đó. :)
Thần chú

Cảm ơn rất nhiều đó là lời giải thích thực sự tuyệt vời. Hiện tại tôi đã thiết lập phát hiện va chạm hộp giới hạn và nếu điều đó xảy ra thì tôi kiểm tra sự chồng chéo pixel giữa hai bitmap nhưng chỉ trong hình chữ nhật chồng chéo. Tất cả điều này hoạt động tuyệt vời và không quá chuyên sâu bộ xử lý. Vấn đề xảy ra khi tôi xoay hình ảnh. Các pixel không được xoay trong bitmap. Tôi chỉ đang vẽ một hình ảnh xoay. Vì vậy, khi tôi tiếp tục kiểm tra xung đột pixel thì nó vẫn sử dụng các pixel cũ. Tôi thích những gì bạn nói về ánh xạ pixel đến tọa độ thế giới. Đây rất có thể là những gì tôi cần làm. Cảm ơn!!!
DRiFTy

+1 Tôi luôn tự hỏi làm thế nào các thuật toán hoạt động, Cảm ơn bạn @DavidGouveia
Vishnu

2

Mặc dù câu trả lời của David Gouveia nghe có vẻ đúng, nhưng đó không phải là giải pháp tốt nhất theo quan điểm hiệu suất. Có một số tối ưu hóa quan trọng bạn cần làm:

  1. sắp xếp và tránh các kiểm tra không cần thiết bằng cách kiểm tra trước bằng một va chạm vòng tròn đơn giản: để lấy tâm và bán kính của các họa tiết của bạn trong bất kỳ phép quay nào, lấy tọa độ cực tiểu và cực đại x và y của cả 4 đỉnh (đã xoay): sau đó bạn có thể xây dựng một vòng tròn đóng trong sprite bởi:

    centre = max_x-min_x / 2, max_y-min_y / 2

    radius = max (max_x-min_x, max_y-min_y)

  2. bây giờ bạn không nên có quá nhiều ứng cử viên để kiểm tra bằng cách raster các hình ảnh đã được chuyển đổi (xoay) về cơ bản bằng cách sử dụng một thuật toán kết cấu affine đơn giản . Về cơ bản, bạn theo dõi 4 dòng trên mỗi sprite rasterized: 2 dòng đi từ đỉnh a đến các đỉnh tiếp theo của hộp xoay của bạn (b và c) 2 dòng đi trong "không gian bitmap" từ đỉnh u1 / v1 đến các đỉnh tiếp theo u2 / v2 và u3 / v3: Lưu ý: Tôi đã googled hình ảnh này và nó hiển thị một hình tam giác, các hộp của bạn chỉ là hai hình tam giác. Điều quan trọng đối với thuật toán này là vẽcác đường ngang (đó là lý do tại sao nó được gọi là " rasterizer ") để tránh "lỗ hổng" bên trong bitmap do lỗi làm tròn. Bằng cách tính toán các dòng với thuật toán bresenham, bạn chỉ cần cho mỗi pixel 4 lần bổ sung và 4 so sánh (và đôi khi là hai lần bổ sung, tùy thuộc vào độ dốc) Những gì bạn làm là bạn viết văn bản đa giác của riêng mình, tuy nhiên không cần chỉnh sửa 3d tốn kém (và khó tối ưu hóa). kết cấu affine

  3. bạn có thể dễ dàng giảm độ phân giải của ảnh bitmap va chạm (ví dụ theo yếu tố 2) và tiết kiệm nhiều thời gian hơn. kiểm tra va chạm trên một nửa độ phân giải shouild không được chú ý.

  4. Nếu bạn đang sử dụng công cụ tích hợp đồ họa, có thể sử dụng một số loại kiểm tra Bộ đệm tăng tốc CTNH (stpson?) Để tránh tự mình mã hóa trình tạo điểm ảnh ..

Vấn đề chính là: Java không nhanh lắm trong việc truy cập dữ liệu bitmap được lưu trữ trong một mảng 2D. Tôi khuyên bạn nên lưu trữ dữ liệu trong một mảng 1 chiều để tránh ít nhất 1 kiểm tra indexOutOfBound cho mỗi lần truy cập. Đồng thời sử dụng kích thước sức mạnh của 2 (như 64x64, 128x128, v.v. Bằng cách này, bạn có thể tính toán bù qua bithifting và không nhân). Bạn cũng có thể tối ưu hóa quyền truy cập kết cấu thứ hai để thực hiện chỉ khi cái đầu tiên có giá trị! = 0 (trong suốt)

Tất cả những vấn đề này đã được giải quyết trong các công cụ kết xuất phần mềm, có thể hữu ích khi xem xét mã nguồn

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.