¿Esquinas redondeadas en XNA?

10

¿Hay alguna manera de hacer esquinas redondeadas en un rectángulo representado en XNA a través de primitivas (tiras de línea)? Quiero hacer que mi interfaz de usuario sea un poco más elegante de lo que ya es, y me gustaría que el código sea flexible, sin demasiadas texturas involucradas.

Mathias Lykkegaard Lorenzen
fuente
Básicamente: use una textura para la línea, una textura para los extremos redondos de la línea. Rotar y escalar sprites que usan estas dos texturas apropiadamente.
Olhovsky

Respuestas:

8

Puede renderizar su primitivo y crear un sombreador que pueda crear estas esquinas redondeadas.
Aquí hay un sombreador de píxeles simple en pseudocódigo que puede dibujar un cuadrado redondeado:

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)

Resultado de este sombreador de píxeles:

ingrese la descripción de la imagen aquí

Si usa sombreadores, puede crear una interfaz de usuario realmente elegante, incluso animada.

Para mí, un gran prototipo de sombreadores de píxeles simples es el programa EvalDraw

piotrek
fuente
5

Otra forma de hacer esto es usar un 'estiramiento de botón' (también llamado 'estiramiento de caja' o 'nueve parches'). Básicamente, crea una imagen que consta de 9 partes:

Recurso de botón

Para dibujar ese botón en cualquier tamaño, dibuja cada pieza (de arriba a abajo, de izquierda a derecha):

  1. Dibuje sin escala en la esquina superior izquierda del rectángulo de destino.
  2. Dibujar escalado horizontalmente (con width - ((1) + (2)).Width ) en la parte superior del rectángulo de destino, con el desplazamiento izquierdo por el ancho de (1).
  3. Dibuje sin escala en la esquina superior derecha del rectángulo de destino.
  4. Dibujar escalado verticalmente (con height - ((1) + (2)).Height ) a la izquierda del rectángulo de destino, con el desplazamiento superior por la altura de (1).
  5. Dibuje escalado en ambas direcciones (con el ancho de (2) y la altura de (4)), compensado por el ancho y la altura de (1).
  6. Dibuje a escala vertical (la misma altura que (4)) a la derecha del rectángulo de destino, compensado por la altura de (1).
  7. Dibuje sin escala en la parte inferior izquierda del rectángulo de destino.
  8. Dibuje escalado horizontalmente (la misma altura que (2)) en la parte inferior del rectángulo de destino, compensado por el ancho de (1).
  9. Dibuje sin escala en la parte inferior derecha del rectángulo de destino.

Si observa el botón, verá que no importa si (2), (5) y (7) se escalan horizontalmente (porque es esencialmente una línea recta); de la misma manera (4), (5) y (6) pueden escalarse verticalmente sin afectar la calidad de la imagen.

Jonathan Dickinson
fuente
Sí, esto no responde la pregunta directamente, pero alguien aún puede encontrarla útil.
Jonathan Dickinson el
44
Se llama un parche de nueve y en realidad es mucho más flexible (¡y más barato!) Que usar un sombreador ya que puedes hacer que se vea como quieras con una textura. Luego puede poner todas sus imágenes de widget en un atlas de textura única. La mayoría de las GUI lo hacen de esta manera.
Elisée
0

Aquí está el código para el enfoque de "nueve parches":

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);
    }
}

Se invoca como:

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
fuente
esto no funciona para mí ... Acabo de obtener un rectángulo normal. Así es como lo uséTexture2D _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
Su textura es solo un píxel azul, este enfoque supone que las esquinas redondeadas son parte de su textura.
sdgfsdh
lo siento, muy nuevo en la plataforma ... gracias por responderme tan rápido
Leonardo Seccia