Câu trả lời:
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;
}
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:
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)
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).
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ú ý.
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