SVG management in DestinE Climate Game ====================================== Presentation ------------ DestinE Climate Game has more than a hundred "Intel cards" informing the player on various subjects linked to ecology. Every card has a singular way of displaying information: we needed to find a way that allowed the authors to edit the cards without breaking the game and for the game to display any card exactly as designed at various resolutions. The SVG Format -------------- The SVG format benefits greatly from its capacity to encapsulates images as well as text. It is the perfect format to display complex information typically seen in educational content. The format itself also provides: * **Scalability and Quality**\ : ability to scale graphics without losing quality. This ensures that the text and vector elements on the "Intel cards" remain crisp and clear, regardless of the screen size or resolution, enhancing the visual experience for players. * **File Size Efficiency**\ : SVG files are generally smaller than raster images for simple graphics, which helps in reducing the game's overall file size. This is particularly beneficial for a game displaying 103 cards, as it optimizes loading times and performance. * **Editability**\ : internally SVG files mimics the architecture of a html webpage. Thus a separation of Raster and Vector Elements is easily possible and by exporting each card into two SVG files—one for raster elements and one for text and vector elements—we ensure that the game can efficiently manage and display complex graphics. This approach allows raster elements to be resized and positioned correctly while keeping vector elements sharp. For the player that would mean: * **Enhanced Visual Experience**\ : By using SVG, players benefit from a visually appealing and clear display of the "Intel cards", with text and vector elements remaining sharp and legible at any size. This improves the overall gaming experience and readability of ecological information. * **Optimized Performance**\ : The use of SVG files helps in optimizing the game's performance by reducing file sizes and ensuring quick loading times. This is crucial for maintaining a smooth and engaging gameplay experience, especially with a large number of cards. * **Consistent and Accurate Display**\ : The separation of raster and vector elements ensures that the cards are displayed accurately, with raster elements resized appropriately and vector elements remaining crisp. This consistency in display helps in conveying the ecological information effectively to the players. Usage ----- Once we determined that the SVG format could be a good fit we managed to adapt its strength and ease the development of "Intel cards". * **Collaborative Editing with Figma**\ : The use of Figma allows multiple authors to edit the "Intel cards" simultaneously in real-time. This collaborative approach streamlines the design process, enabling quick updates and modifications to the card content related to ecology. * **Export Process**\ : As evoked in a previous point, authors needed to follow a consistent export process to integrate the cards into the game. Each card must be exported twice: once with all raster elements (as a .png file) and once as a vectorial export (as a .svg file, with only text and shape elements). This ensures compatibility with the game's resizing requirements. We initially wrote a python script (ConvertSVG.py) that made it automatically but we found a solution directly in Figma that needed less than 4 clicks so that was the final method used. * **Integration with GODOT**\ : Using an **custom SVG interface** developed in GODOT, the exported SVG files are easily integrated into the game engine, allowing for seamless display and interaction within the game. This process ensures that the cards are correctly rendered and maintain their intended design and functionality. Each card can be tested from the editor to ensure that the render is flawless. Custom SVG interface -------------------- Decks ^^^^^ "Intel cards" have different subjects and could thus be classified into different categories. The class "IntelCardDeck" is a collection of "Intel cards" that are from the same type. The class extends ``Resource`` so that it could be seen as a readable asset by GODOT. A deck defines the main color, header text and icons for all its cards. The ``intelCards`` variable is an array of .svg files that correspond to the vectorial export mentioned earlier. .. code-block:: class_name IntelCardDeck extends Resource enum Type { AGRICULTURE, AMAZON, ARCTIC, ATMOSPHERE, CITIES, EXTREMEVENTS, GREATAUSTRALIANBARRIER, IPCC, MADRID, NILEDELTA, SIBERIANTAIGAFOREST, TREE, WATER, ICE, RIVER, BONUS, COUNT, NONE = -1 # keep last } @export var type: Type @export var intelCards: Array[Texture2D] = [] @export var labelName : String @export var icon : Texture2D @export var color : Color GameUIData ^^^^^^^^^^ Decks can be added and modified through the ``GameUIData`` asset. Once a card is added it can be previewed by opening the ``IntelCardViewer.tscn`` scene. IntelCardViewer ^^^^^^^^^^^^^^^ GODOT allows any script to be run in the editor by simply adding ``@tool`` at the start of the class. Using this tag we modify the behavior of the script that displays "Intel cards" in the ``IntelCardViewer.tscn`` scene to preview how the game would display any card. .. code-block:: @tool class_name IntelCardViewer @export var cardPNGViewer: TextureRect @export_global_file("*.svg") var preview: set(value): if value == "" || value == null: return preview = "res://Content" + value.split("/Content")[1] var intelCardContent = null var localDecks = ResourceLoader.load("res://Game/GameUIData.tres", "GameUIData").decks for deck in localDecks: for card in deck.intelCards: if card.resource_path == preview: intelCardContent = IntelCardViewer.Content.new(card, deck.labelName, deck.icon, deck.color) if intelCardContent == null: print("Error loading texture: res not found") return cardPNGViewer.texture = null OpenIntelCard(intelCardContent, load(preview.replace(".svg", ".png"))) As we can see here, opening a .svg file via the ``preview`` variable executes a function that will search through ``GameUIData``\ , to find a corresponding deck. If found, we call ``OpenIntelCard`` which is the same function that we call in-game but with an additional parameter which would be the raster version of the file (the .png file explained previously in the **\ *Export Process*\ ** section). Additional information ^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: @tool class_name IntelCardViewer @export var sourcesContainer: Control @export var abbreviationsContainer: RichTextLabel @export_multiline var sources: String: set(value): var sliderButton = Utils.FindNodeWithType(self, SliderButton) sources = value if Engine.is_editor_hint(): sourcesContainer.visible = value != "" sliderButton.displayText = "Sources" if value != "" else "" sliderButton.button.disabled = value == "" self.find_child("Sources").text = value save = false @export var abbreviations: String: set(value): abbreviations = value abbreviationsContainer.text = value + " " save = false @export var save : bool: set(value): if value == true: var uiData = ResourceLoader.load("res://Game/GameUIData.tres", "GameUIData") var tmp : Dictionary = uiData.misc.duplicate() tmp[preview] = { "sources" : sources, "abbreviations" : abbreviations } uiData.misc = tmp ResourceSaver.save(uiData) save = value Once loaded an "Intel card" can optionally have multiple additional information such as abbreviations and sources. Unlike the main content that vary from card to card, sources and abbreviations are better suited for a standardized display. So instead of adding them in the figma we add them in this preview process. Sources are displayed on top of everything with the help of a button and can be copied by the player. Both information are stored in ``GameUIData``.