Abgerundete Ecken in XNA?

10

Gibt es eine Möglichkeit, abgerundete Ecken auf einem in XNA gerenderten Rechteck durch Grundelemente (Linienstreifen) zu erstellen? Ich möchte meine Benutzeroberfläche etwas ausgefallener gestalten als sie bereits ist, und ich möchte, dass der Code flexibel ist, ohne dass zu viele Texturen beteiligt sind.

Mathias Lykkegaard Lorenzen
quelle
Grundsätzlich gilt: Verwenden Sie eine Textur für die Linie, eine Textur für die runden Enden der Linie. Drehen und skalieren Sie Sprites, die diese beiden Texturen verwenden.
Olhovsky

Antworten:

8

Sie können Ihr Grundelement rendern und einen Shader erstellen, mit dem diese abgerundeten Ecken erstellt werden können.
Hier ist ein einfacher Pixel-Shader im Pseudocode, der ein abgerundetes Quadrat zeichnen kann:

xDist = abs(x-0.5)
yDist = abs(y-0.5)
xD = xDist*xDist*4
yD = yDist*yDist*4
alpha = floor((1-xD)*(1-yD)*5)

Ergebnis dieses Pixel-Shaders:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie Shader verwenden, können Sie eine wirklich ausgefallene Benutzeroberfläche erstellen, sogar eine animierte.

Für mich ist das Programm EvalDraw ein großartiger Prototyp für einfache Pixel-Shader

Piotrek
quelle
5

Eine andere Möglichkeit, dies zu tun, ist die Verwendung eines "Button Stretch" (auch als "Box Stretch" oder "Nine-Patch" bezeichnet). Im Wesentlichen erstellen Sie ein Bild, das aus 9 Teilen besteht:

Schaltflächenressource

Um diesen Knopf in einer beliebigen Größe zu zeichnen, zeichnen Sie jedes Stück (von oben nach unten, von links nach rechts):

  1. Zeichnen Sie unskaliert oben links im Zielrechteck.
  2. Zeichnen Sie horizontal skaliert (mit width - ((1) + (2)).Width) am oberen Rand des Zielrechtecks, wobei die linke Seite um die Breite von (1) versetzt ist.
  3. Zeichnen Sie unskaliert oben rechts im Zielrechteck.
  4. Zeichnen Sie vertikal (mit height - ((1) + (2)).Height) links vom Zielrechteck skaliert , wobei die Oberseite um die Höhe von (1) versetzt ist.
  5. Zeichnen Sie in beide Richtungen skaliert (mit der Breite von (2) und der Höhe von (4)), versetzt um die Breite und Höhe von (1).
  6. Zeichnen Sie vertikal skaliert (gleiche Höhe wie (4)) rechts vom Zielrechteck, versetzt um die Höhe von (1).
  7. Zeichnen Sie unskaliert unten links im Zielrechteck.
  8. Zeichnen Sie horizontal skaliert (gleiche Höhe wie (2)) am unteren Rand des Zielrechtecks, versetzt um die Breite von (1).
  9. Zeichnen Sie unskaliert unten rechts im Zielrechteck.

Wenn Sie sich die Schaltfläche ansehen, werden Sie feststellen, dass es keine Rolle spielt, ob (2), (5) und (7) horizontal skaliert werden (da es sich im Wesentlichen um eine gerade Linie handelt). Auf die gleiche Weise können (4), (5) und (6) vertikal skaliert werden, ohne die Bildqualität zu beeinträchtigen.

Jonathan Dickinson
quelle
Ja, dies beantwortet die Frage nicht direkt - aber jemand könnte sie dennoch nützlich finden.
Jonathan Dickinson
4
Es wird als Neun-Patch bezeichnet und ist tatsächlich viel flexibler (und billiger!) Als die Verwendung eines Shaders, da Sie es mit einer Textur so aussehen lassen können, wie Sie möchten. Sie können dann alle Ihre Widget-Bilder in einem einzigen Texturatlas ablegen. Die meisten GUIs machen das so.
Elisée
0

Hier ist der Code für den "Neun-Patch" -Ansatz:

public static class SpriteBatchExtensions
{
    public static void DrawRoundedRect(this SpriteBatch spriteBatch, Rectangle destinationRectangle, 
        Texture2D texture, int border, Color color)
    {
        // Top left
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location, new Point(border)), 
            new Rectangle(0, 0, border, border), 
            color);

        // Top
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(border, 0), 
                new Point(destinationRectangle.Width - border * 2, border)), 
            new Rectangle(border, 0, texture.Width - border * 2, border), 
            color);

        // Top right
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(destinationRectangle.Width - border, 0), new Point(border)), 
            new Rectangle(texture.Width - border, 0, border, border), 
            color);

        // Middle left
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(0, border), new Point(border, destinationRectangle.Height - border * 2)), 
            new Rectangle(0, border, border, texture.Height - border * 2), 
            color);

        // Middle
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(border), destinationRectangle.Size - new Point(border * 2)), 
            new Rectangle(border, border, texture.Width - border * 2, texture.Height - border * 2), 
            color);

        // Middle right
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(destinationRectangle.Width - border, border), 
                new Point(border, destinationRectangle.Height - border * 2)), 
            new Rectangle(texture.Width - border, border, border, texture.Height - border * 2), 
            color);

        // Bottom left
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(0, destinationRectangle.Height - border), new Point(border)), 
            new Rectangle(0, texture.Height - border, border, border), 
            color);

        // Bottom
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(border, destinationRectangle.Height - border), 
                new Point(destinationRectangle.Width - border * 2, border)), 
            new Rectangle(border, texture.Height - border, texture.Width - border * 2, border), 
            color);

        // Bottom right
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + destinationRectangle.Size - new Point(border), new Point(border)), 
            new Rectangle(texture.Width - border, texture.Height - border, border, border), 
            color);
    }
}

Es wird aufgerufen als:

spriteBatch.DrawRoundedRect(
    dest, // The coordinates of the Rectangle to be drawn
    rectangleTexture, // Texture for the whole rounded rectangle
    16, // Distance from the edges of the texture to the "middle" patch
    Color.OrangeRed);
sdgfsdh
quelle
Das funktioniert bei mir nicht ... Ich bekomme nur ein normales Rechteck. So habe ich es benutztTexture2D _texture = new Texture2D(GraphicsDevice, 1, 1); _texture.SetData(new Color[] { Color.Blue }); SpriteBatch sb = new SpriteBatch(GraphicsDevice); sb.Begin(); //sb.Draw(_texture, new Rectangle(100, 100, 100, 100), Color.White); sb.DrawRoundedRect(_texture, new Rectangle(100, 100, 100, 100), Color.Pink, 16); sb.End();
Leonardo Seccia
Ihre Textur ist nur ein blaues Pixel. Bei diesem Ansatz wird davon ausgegangen, dass die abgerundeten Ecken Teil Ihrer Textur sind.
SDGFSDH
Entschuldigung - sehr neu auf der Plattform ... danke, dass Sie sich so schnell bei mir
gemeldet haben