En el tutorial anterior, cubrimos los conceptos básicos del uso de gráficos en SFML. Sin embargo, lo más probable es que tu juego no se componga de formas simples, sino que se componga de muchos sprites. Eso es exactamente lo que vamos a cubrir hoy.
Como siempre, hay una versión HD de este tutorial disponible aquí.
En primer lugar, debemos comenzar definiendo qué es exactamente un Sprite. En los primeros días de las computadoras, sprite tenía un significado especial, ya que literalmente había hardware sprite integrado en las primeras computadoras de 8 bits. Un sprite es básicamente una imagen en pantalla que se puede mover. Eso es todo. En SFML esta relación se demuestra fácilmente por su jerarquía de clases.
Sin embargo, hay un concepto muy clave para entender con los sprites. Un sprite en SFML representa una imagen o textura en la pantalla que se puede mover. Sin embargo, ¡no posee la textura o la imagen! Esto hace que la clase Sprite sea bastante liviana, lo que ciertamente no es cierto para Textura o Imagen, las clases que en realidad contienen todos los datos en la imagen. Tal vez sea más fácil comenzar con una simple demostración.
Primero, necesitamos una imagen con la que trabajar. Estoy usando un sprite de dragón del reciente Paquete Humble Indie Gamedev. La imagen se ve así:
Obviamente, puede usar cualquier imagen que desee, solo asegúrese de copiarla en el directorio de trabajo de su aplicación. En Visual Studio, el directorio de trabajo se puede ubicar en el panel de propiedades del proyecto en Depuración llamado Directorio de trabajo:
La imagen puede tener cualquiera de los siguientes formatos: bmp, hdr, gif, jpg, png, pic, psd, tga. Tenga en cuenta que no todos los formatos son iguales. Los mapas de bits, por ejemplo, no admiten la codificación de transparencia y, por lo general, son bastante grandes, pero no pierden detalles de la imagen y es fácil trabajar con ellos. Gif tiene algunos problemas de patentes y, en general, debe evitarse. Png parece realmente una buena combinación entre características, tamaño y calidad, y está bien respaldado por las herramientas de creación de contenido.
Ok, suficiente configuración, vamos a llegar a un poco de código.
// Demonstrate sprite drawing in SFML #include "SFML/Graphics.hpp" int main(int argc, char ** argv){ sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game"); sf::Event event; sf::Texture texture; texture.loadFromFile("images/dragonBig.png"); sf::Sprite sprite(texture); while (renderWindow.isOpen()){ while (renderWindow.pollEvent(event)){ if (event.type == sf::Event::EventType::Closed) renderWindow.close(); } renderWindow.clear(); renderWindow.draw(sprite); renderWindow.display(); } }
Y cuando ejecutas eso:
Como puede ver, la experiencia es notablemente consistente con el dibujo usando primitivas gráficas. La gran diferencia aquí es que creamos nuestro Sprite proporcionando una textura, que a su vez cargamos desde un archivo con una llamada a Textura::loadFromFile(). Existen métodos para cargar desde la transmisión o la memoria, si se prefiere. De nuevo es importante recordar que el Sprite no no poseer la textura. Esto significa que si la textura sale del alcance antes que el Sprite, el sprite dibujará un rectángulo en blanco. Esto también significa que varios sprites pueden usar la misma textura.
Ahora te habrás dado cuenta de que además de sf::Texturahay una clase llamada sf::Imagen y te estarás preguntando por qué. Hay una diferencia muy simple en juego aquí. Una textura reside en la memoria de su tarjeta gráfica, mientras que una imagen reside en la memoria del sistema. El acto de copiar una imagen de la memoria del sistema a la GPU es bastante costoso, por lo que, por razones de rendimiento, es casi seguro que desee utilizar Texture. Dicho esto, Texture no se modifica fácilmente, por lo que si está trabajando en una textura dinámica o, por ejemplo, creando una captura de pantalla, Image es la mejor opción. Existen métodos para cambiar entre los dos tipos, pero también tienen un rendimiento bastante pesado, así que no los haga cuadro por cuadro. Al final del día
A continuación, echemos un vistazo rápido a la creación de una imagen dinámica. No es algo que vayas a hacer con frecuencia en la mayoría de los juegos, pero tiene sentido mencionarlo ahora.
// Demonstrate creating an Image #include "SFML/Graphics.hpp" int main(int argc, char ** argv){ sf::RenderWindow renderWindow(sf::VideoMode(640, 480), "Demo Game"); sf::Event event; sf::Image image; image.create(640, 480, sf::Color::Black); bool isBlackPixel = false; sf::Color blackPixel(0,0,0,255); sf::Color whitePixel(255, 255, 255, 255); //Loop through each vertical row of the image for (int y = 0; y < 480; y++){ //then horizontal, setting pixels to black or white in blocks of 8 for (int x = 0; x < 640; x++){ if (isBlackPixel) image.setPixel(x, y, blackPixel); else image.setPixel(x, y, whitePixel); // Every 8th flip colour if (!(x % 8)) isBlackPixel = !isBlackPixel; } // Offset again on vertical lines to create a checkerboard effect if(!(y%8)) isBlackPixel = !isBlackPixel; } sf::Texture texture; texture.loadFromImage(image); sf::Sprite sprite(texture); while (renderWindow.isOpen()){ while (renderWindow.pollEvent(event)){ if (event.type == sf::Event::EventType::Closed) renderWindow.close(); } renderWindow.clear(); renderWindow.draw(sprite); renderWindow.display(); } }
Cuando ejecute este ejemplo, debería ver:
Aquí puede ver que podemos modificar los píxeles directamente en nuestra sf::Image. Sin embargo, para mostrarlo en la pantalla aún necesitamos moverlo a la textura y llenar un sprite. La diferencia es el acceso directo a los datos de píxeles. Otra capacidad importante de sf::Image es el método saveToFile que le permite guardar en un archivo. Obviamente útil para crear capturas de pantalla y tareas similares.
Es posible que observe, según la resolución o la composición de la imagen de origen, que la textura puede no verse exactamente como su imagen de origen. Esto se debe a que hay un filtro de suavizado o suavizado integrado en SFML para que las imágenes se vean más suaves. Si no desea esto, tal vez buscando ese aspecto grueso de 8 bits, puede desactivarlo con una llamada a setSmooth(false);
Eso es todo lo que vamos a cubrir hoy. En la siguiente parte del tutorial, veremos las hojas de sprites, para que podamos tener múltiples sprites diferentes en una sola imagen de origen.