Antworten:
Ich bin mit Android nicht vertraut, daher weiß ich nicht, welche Tools Ihnen zur Verfügung stehen, aber ich kann Ihnen einen Weg nennen, dies allgemein zu implementieren. Wie einfach es sein wird, hängt davon ab, was Android für Sie bereitstellt. Sie werden Matrizen benötigen oder zumindest die Berechnungen erheblich vereinfachen.
Führen Sie zunächst eine Bounding-Box-Kollisionsprüfung durch und kehren Sie sofort zurück, wenn sie nicht kollidieren, um weitere Berechnungen zu vermeiden. Das ist logisch, denn wenn die Begrenzungsrahmen nicht kollidieren, wird garantiert, dass auch keine Pixel kollidieren.
Wenn anschließend eine pixelgenaue Kollisionsprüfung erforderlich ist, ist der wichtigste Punkt, dass Sie diese Prüfung an derselben Stelle durchführen müssen . Dies kann erreicht werden, indem jedes Pixel aus Sprite A entnommen, eine Reihe von Transformationen angewendet wird, um sie in den lokalen Raum von Sprite B zu bringen, und dann überprüft wird, ob es mit einem Pixel an dieser Position auf Sprite B kollidiert. Eine Kollision tritt auf, wenn beide Pixel geprüft sind undurchsichtig.
Das erste, was Sie brauchen, ist, eine Weltmatrix für jeden der Sprites zu erstellen. Es gibt wahrscheinlich Online-Tutorials, in denen Sie lernen, wie man eine erstellt, aber im Grunde sollte es sich um eine Verkettung einiger einfacherer Matrizen in der folgenden Reihenfolge handeln:
Translation(-Origin) * Scale * Rotation * Translation(Position)
Der Nutzen dieser Matrix besteht darin, dass durch Multiplizieren eines Punkts im lokalen Raum - und wenn Sie beispielsweise die Pixel mit einer Methode wie bitmap.getPixelAt(10,20)
dieser erhalten, 10,20 im lokalen Raum definiert werden - durch die entsprechende Weltmatrix in den Weltraum verschoben wird:
LocalA * WorldMatrixA -> World
LocalB * WorldMatrixB -> World
Und wenn Sie die Matrizen invertieren , können Sie auch in die entgegengesetzte Richtung gehen, dh Punkte aus dem Weltraum in jeden der lokalen Räume des Sprites transformieren, je nachdem, welche Matrix Sie verwendet haben:
World * InverseWorldMatrixA -> LocalA
World * InverseWorldMatrixB -> LocalB
Um einen Punkt aus dem lokalen Raum von Sprite A in den lokalen Raum von Sprite B zu verschieben , transformieren Sie ihn zuerst mit der Weltmatrix von Sprite A, um ihn in den Weltraum zu bringen, und verwenden Sie dann die inverse Weltmatrix von Sprite B , um ihn zu erhalten Der lokale Raum von Sprite B:
LocalA * WorldMatrixA -> World * InverseWorldMatrixB -> LocalB
Nach der Transformation überprüfen Sie, ob der neue Punkt innerhalb der Grenzen von Sprite B liegt, und wenn dies der Fall ist, überprüfen Sie das Pixel an dieser Stelle genau wie bei Sprite A. Der gesamte Prozess wird also ungefähr so (in Pseudocode und ungetestet). ::
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;
}
Die Antwort von David Gouveia klingt zwar richtig, ist jedoch aus Sicht der Leistung nicht die beste Lösung. Es gibt mehrere wichtige Optimierungen, die Sie vornehmen müssen:
Sortieren und vermeiden Sie unnötige Überprüfungen, indem Sie zuerst mit einer einfachen Kreiskollision prüfen: Um den Mittelpunkt und den Radius Ihrer Sprites bei jeder Drehung zu ermitteln, ermitteln Sie die Minima und Maxima x- und y-Koordinaten aller 4 (bereits gedrehten) Scheitelpunkte. Anschließend können Sie konstruieren ein Kreis, der sich im Sprite schließt durch:
center = max_x-min_x / 2, max_y-min_y / 2
Radius = max (max_x-min_x, max_y-min_y)
Jetzt sollten Sie nicht zu viele Kandidaten haben, um sie zu überprüfen, indem Sie die bereits transformierten (gedrehten) Bilder grundsätzlich mithilfe eines einfachen affinen Texturabbildungsalgorithmus rastern . Grundsätzlich verfolgen Sie 4 Linien pro gerastertem Sprite: 2 Linien vom Scheitelpunkt a zu den nächsten Scheitelpunkten Ihrer gedrehten Box (b und c) 2 Linien im "Bitmap-Raum" vom Scheitelpunkt u1 / v1 bis zu den nächsten Scheitelpunkten u2 / v2 und u3 / v3: Hinweis: Ich habe dieses Bild gegoogelt und es zeigt ein Dreieck. Ihre Felder sind nur zwei Dreiecke. Für diesen Algorithmus ist es wichtig, horizontale Linien zu zeichnen (deshalb wird er als " Rasterizer " bezeichnet), um "Löcher" in der Bitmap aufgrund von Rundungsfehlern zu vermeiden. Durch Berechnung der Linien mit einem Bresenham-AlgorithmusSie benötigen für jedes Pixel nur 4 Additionen und 4 Vergleiche (und manchmal zwei zusätzliche Additionen, abhängig von der Steigung). Sie schreiben Ihren eigenen Polygon-Textur-Mapper, jedoch ohne die kostspielige (und schwer zu optimierende) 3D-Korrektur.
Sie können die Auflösung der Kollisionsbitmaps leicht reduzieren (z. B. um Faktor 2) und noch mehr Zeit sparen. Eine Kollisionsprüfung der Hälfte der Auflösung sollte nicht bemerkt werden.
Wenn Sie die Grafikbeschleunigung verwenden, können Sie möglicherweise eine Art HW-beschleunigten Puffercheck (Schablone?) Verwenden, um zu vermeiden, dass Sie den Rasterizer selbst codieren.
Das Hauptproblem ist: Java ist beim Zugriff auf in einem 2D-Array gespeicherte Bitmap-Daten nicht sehr schnell. Ich würde empfehlen, die Daten in einem eindimensionalen Array zu speichern, um mindestens 1 indexOutOfBounds-Prüfung für jeden Zugriff zu vermeiden. Verwenden Sie auch Zweierpotenz-Dimensionen (wie 64 x 64, 128 x 128 usw. Auf diese Weise können Sie den Versatz über Bitverschiebung und nicht über Multiplikation berechnen). Sie können den zweiten Texturzugriff auch so optimieren, dass er nur ausgeführt wird, wenn der erste den Wert! = 0 (transparent) hat.
All diese Probleme wurden in Software-Rendering-Engines gelöst. Es könnte nützlich sein, den Quellcode zu untersuchen