2016-06-06 12 views
0

Gerade jetzt für die Drehung habe ich einen separaten Rahmen für jeden Drehwinkel, aber ich habe viel eher ein Bild, das ich rotiere. Meine Frage ist, wie mache ich eine Matrix-Transformation in XNA/C#, so dass die Farbdaten ebenfalls genauso gedreht werden, wie das Sprite auf dem Bildschirm gerendert wird? Ich habe dieses alte SO question gefunden, aber ich verstehe die Antwort wirklich nicht, und ich würde gerne wissen, wie der Code funktioniert, falls er später geändert werden muss.XNA: Kollisionen zwischen rotierenden Sprites

Alle erforderlichen Positions-/Rotationsinformationen werden in der Entität gespeichert, die das Sprite enthält, und es wird angenommen, dass beide Sprites rotieren.

Hier ist mein Code so weit:

private static bool PixelPerfect(PhysicsEntity a, PhysicsEntity b) 
    { 
     if (!BoundingBox(a, b)) return false; 

     var colorDataA = new Color[a.Sprite.Source.Width * a.Sprite.Source.Height]; 
     var colorDataB = new Color[b.Sprite.Source.Width * b.Sprite.Source.Height]; 

     a.Sprite.Texture.GetData(0, a.Sprite.Source, colorDataA, 0, colorDataA.Length); 
     b.Sprite.Texture.GetData(0, b.Sprite.Source, colorDataB, 0, colorDataB.Length); 

     var top = (int) Math.Max(a.BoundingBox.Top, b.BoundingBox.Top); 
     var bottom = (int) Math.Min(a.BoundingBox.Bottom, b.BoundingBox.Bottom); 
     var left = (int) Math.Max(a.BoundingBox.Left, b.BoundingBox.Left); 
     var right = (int) Math.Min(a.BoundingBox.Right, b.BoundingBox.Right); 

     for (var y = top; y < bottom; y++) 
     { 
      for (var x = left; x < right; x++) 
      { 
       var colorA = colorDataA[(int) ((y - a.BoundingBox.Top) * (a.BoundingBox.Width) + (x - a.BoundingBox.Left))]; 
       var colorB = colorDataB[(int) ((y - b.BoundingBox.Top) * (a.BoundingBox.Width) + (x - a.BoundingBox.Left))]; 
       if (colorA.A == 0 || colorB.A == 0) continue; 
       a.CollisionPoint.ChangePositon(x, y); 
       b.CollisionPoint.ChangePositon(x, y); 
       return true; 
      } 
     } 
     return false; 
    } 

Antwort

0

Sie die Daten konstant halten sollte. Sie ändern nur die Art, wie Sie darauf zugreifen.

Für eine pixelgenaue Kollisionserkennung lautet die Grundidee: Sie haben zwei Sprites, die mit den Transformationsmatrizen m1 bzw. m2 gerendert werden. Iteriere nun jedes Pixel von Sprite 1. Finde heraus, an welcher Bildschirmposition sich dieses Pixel befindet. Finde das Pixel von Sprite 2, das sich an der gleichen (oder ähnlichen) Position befindet.

Die Transformationsmatrizen sind in der Regel so etwas wie

t = Matrix.CreateRotationZ(angle) * Matrix.CreateTranslation(position); 

Sie Ihre Matrixberechnung mit der Überlastung der SpriteBatch.Begin() überprüfen, die eine Matrix nimmt.

Die Transformation von Pixelraum des Sprites 1 für den Weltraum ist:

worldPos = sprite1LocalPos * m1 

Die Raumtransformation Form Welt 2 der Pixelraum Sprite ist:

sprite2LocalPos = worldPos * Matrix.Invert(m2) 
       = sprite1LocalPos * m1 * Matrix.Invert(m2) 

Und das ist im Grunde alles, was Sie brauchen, um tun:

Matrix transform = m1 * Matrix.Invert(m2); 
Rectangle rect = new Rectangle(0, 0, texture2.Width, texture2.Height); 
for (int x = 0; x < texture1.Width; x++) 
{ 
    for (int y = 0; y < texture1.Height; y++)  //Iterate every pixel of sprite 1 
    { 
     index = x + texture1.Width * y;    //Calculate the pixel index 
     if (data1[index].A < 10)     //If the pixel is (almost) transparent, 
      continue;        //ignore it 

     Vector2 sprite1Local = new Vector2(x, y); 
     Vector2 sprite2Local        //get the pixel of sprite 2 
      = Vector2.Transform(sprite1Local, transform); //that is at the same position 

     if(!rect.Contains((int)sprite2Local.X, (int)sprite2Local.Y)) 
                //if this is outside of the sprite, 
      continue;        //ignore it 

     index2 = (int)sprite2Local.X + (int)sprite2Local.Y * texture2.Width; 
     if(data2[index2].A>10)      //If the pixel is not transparent, 
      return true;       //there is a collision 
    } 
} 
return false; 
Verwandte Themen