En este post voy a documentar el proceso de como modificar la ui de intersect, el plan es comenzar por la pantalla principal y las ventanas de login, registro, configuraciones, y créditos.

¿Cómo funciona la UI de Intersect?

El motor usa un framework llamado Gwen con una arquitectura de 3 capas:

├─────────────────────────────────────────────────────────┤
CAPA 1: Imágenes (recursos/gui/*.png)
REEMPLAZO DIRECTO – NO requiere recompilación

En esta carpeta de \resources\gui podemos editar los botones principales del login y muchas cosas de la interfaz con tan solo con remplazar las imágenes que se encuentran ahi, en mi caso solo agregare background.png y logo.png.
├─────────────────────────────────────────────────────────┤
CAPA 2: JSON LAYOUTS (recursos/gui/layouts/menu/)
EDICIÓN SIMPLE – NO requiere recompilación

Cada control en el JSON tiene estas propiedades:

{
  // POSICIÓN Y TAMAÑO
  "Bounds": "x,y,width,height",    // Coordenadas y dimensiones
  "Dock": "None|Fill|Top|Bottom|Left|Right",  // Sistema de dock
  "Margin": "l,t,r,b",             // Margen externo
  "Padding": "l,t,r,b",            // Relleno interno
  
  // ALINEACIÓN
  "Alignments": "CenterH|CenterV|Center|Top|Bottom|Left|Right",
  "AlignmentEdgeDistances": "0,0,0,0",
  "AlignmentTransform": "0,0",
  
  // COLORES (formato ARGB: 0-255,0-255,0-255,0-255)
  "RenderColor": "255,255,255,255",    // Color de mezcla
  "TextColor": "255,255,255,255",      // Color de texto
  "HoveredTextColor": "255,200,100,255",
  "ClickedTextColor": "255,150,50,255",
  "DisabledTextColor": "128,128,128,255",
  
  // VISIBILIDAD
  "Hidden": false,
  "Disabled": false,
  "DrawBackground": true,
  "DrawShadow": true,
  
  // FUENTES
  "FontName": "sourcesansproblack",    // Nombre de fuente
  "FontSize": 12,                       // Tamaño en puntos
  "TextScale": 1.0,                     // Escala adicional
  "TextAlign": "Center|CenterV|Left|Right|Top|Bottom",
  
  // TEXTURAS DE BOTONES
  "NormalImage": "mainmenu_buttonLogin.png",
  "HoveredImage": "mainmenu_buttonLogin_hovered.png",
  "ClickedImage": "mainmenu_buttonLogin_clicked.png",
  "DisabledImage": "mainmenu_buttonLogin_disabled.png",
  
  // SONIDOS
  "_stateSoundNames": {
    "Hover": "octave-tap-resonant.wav",
    "MouseDown": "octave-tap-warm.wav",
    "MouseUp": "octave-tap-warm.wav"
  },
  
  // TAMAÑOS MÍNIMOS/MÁXIMOS
  "MinimumSize": "160,24",
  "MaximumSize": "0,0",
  
  // CONTROL DE INTERACCIÓN
  "MouseInputEnabled": true,
  "AutoSizeToContents": false,
  
  // CONTROLES HIJO
  "Children": {
    "_usernameLabel": { ... },
    "_usernameInput": { ... }
  }
}

Un Ejemplo para poder cambiar el color de la ventana principal del login,
en MaimMenuWindows_online.json se modifica el primer RenderColor.

en resources/config.json podemos personalizar el menú con algunas opciones:

{
  // FUENTES
  "GameFont": "sourcesansproblack",           // Fuente principal
  "EntityNameFont": "sourcesansproblack",     // Nombres de entidades
  "ChatBubbleFont": "sourcesansproblack",    // Burbujas de chat
  "UIFont": "sourcesanspro,10",              // Fuente UI general
  
  // FONDO DEL MENÚ
  "MenuBackground": ["background.png"],        // Array de imágenes (puede haber varias para slideshow)
  "MenuBackgroundDisplayMode": "Default",     // Modo de display
  "MenuBackgroundFrameInterval": 50,          // Ms entre frames de slideshow (50ms = 20fps)
  
  // MÚSICA
  "MenuMusic": "RPG-Theme_v001_Looping.ogg",
  "MusicFadeTimer": 1500,                     // Ms para fade out de música
  
  // SKIN DE UI
  "UiSkin": "IntersectSkin",                 // Skin a usar (avanzado)
  
  // EFECTOS
  "TypewriterEnabled": true,                 // Efecto de máquina de escribir en texto
  "FadeDurationMs": 3000.0,                  // Duración de fade en ms
  
  // MISC
  "EnableContextMenus": true,                // Menús contextuales
  "EnableZebraStripedRows": true             // Filas alternadas en listas
}

Modos de Display del Fondo

ModoDescripción
DefaultCentrado, puede dejar barras negras
CenteredCentrado exactamente
StretchedEstirado a pantalla completa (deforma)
FitHeightAjusta a altura, mantiene proporción
FitWidthAjusta a ancho, mantiene proporción
FitMaximumEscala hacia arriba hasta llenar pantalla
FitMinimumEscala hacia abajo hasta llenar pantalla


├─────────────────────────────────────────────────────────┤
CAPA 3: CÓDIGO C# (código fuente/*.cs)
REQUIERE RECOMPILACIÓN

Flujo de carga de una ventana

1. MainMenu.cs crea la ventana
   ↓
2. Constructor de LoginWindow.cs
   - Crea todos los controles (TextBox, Button, Label)
   - Configura propiedades base (tamaño, fuentes, colores)
   - Asigna event handlers (Clicked, SubmitPressed, etc.)
   ↓
3. EnsureInitialized() se llama automáticamente
   ↓
4. LoadJsonUi() carga el JSON
   - Busca: resources/gui/layouts/menu/LoginWindow.json
   - Aplica propiedades del JSON sobre las del código
   - Procesa alineaciones
   ↓
5. OnJsonReloaded() - hook para post-procesamiento

Ejemplo: Crear una ventana completamente nueva

// 1. Crear clase que herede de Window
public class CustomWindow : Window, IMainMenuWindow
{
    public CustomWindow(Canvas parent, MainMenu mainMenu) : base(
        parent,
        title: "Mi Ventana Personalizada",
        modal: false,
        name: nameof(CustomWindow)
    )
    {
        // Configuración inicial
        Alignment = [Alignments.CenterH];
        MinimumSize = new Point(400, 300);
        
        // Crear controles...
    }
    
    protected override void EnsureInitialized()
    {
        LoadJsonUi(GameContentManager.UI.Menu, 
                   Graphics.Renderer?.GetResolutionString());
    }
}

// 2. Registrar en MainMenu.cs
private CustomWindow? _customWindow;
public CustomWindow CustomWindow => _customWindow ??= new CustomWindow(_menuCanvas, this);

// 3. Agregar navegación
internal void SwitchToWindow<TMainMenuWindow>() where TMainMenuWindow : IMainMenuWindow
{
    // ...código existente...
    if (typeof(TMainMenuWindow) == typeof(CustomWindow))
    {
        CustomWindow.Show();
    }
}


├─────────────────────────────────────────────────────────┤

Cambiar nombre del ejecutable

Hacer 3 modificaciones para no generar errores:

1.-En /Intersect.Client/Intersect.Client.csproj
<AssemblyName>Mini RPG</AssemblyName>

2.-En /Intersect.Client.Core/Intersect.Client.Core.csproj
<_Parameter1>Mini RPG</_Parameter1>

3.-En /Intersect-Engine/Framework/Intersect.Framework.Core.csproj
<_Parameter1>Mini RPG</_Parameter1>

Cambiar el icono de intersect

-Para cambiar el icono se puede realizar presionando Ctrl + mayus + F y buscar en todas las ubicaciones que tengan el nombre del logo de Intersect (intersect-logo-qu) que se encuentra en la carpeta Assets.

1.-en Intersect-Engine/Intersect.Client/Intersect.Client.csproj
<EmbeddedResource Include=»$(IntersectRepoPath)\assets\sharingan.bmp»>

2.-en Intersect-Engine/Intersect.props/
<PackageIcon>$(IntersectRepoPath)\assets\sharingan.png
<ApplicationIcon>$(IntersectRepoPath)\assets\sharingan.ico
<None Include=»$(IntersectRepoPath)\assets\sharingan.png» Pack=»true» PackagePath=»\» />
<EmbeddedResource Include=»$(IntersectRepoPath)\assets\sharingan.ico» Pack=»true» PackagePath=»\» />

3.-En Intersect-Engine\Intersect.Client.Framework\Intersect.Client.Framework.nuspec\
assets\sharingan.png
<icon>assets\sharingan.png</icon>
<file src=»..\assets\sharingan.png» target=»assets» />

4.-En \Intersect-Engine\Intersect.Editor\Core\Program.cs
private const string IconManifestResourceName = «Intersect.Editor.sharingan.ico»;

5.-En \Intersect-Engine\Intersect.Server.Framework\Intersect.Server.Framework.nuspec
assets\sharingan.png
<icon>assets\sharingan.png</icon>
<file src=»..\assets\sharingan.png» target=»assets» />

6.-En \Intersect-Engine\Intersect.SinglePlayer\Intersect.SinglePlayer.csproj
<EmbeddedResource Include=»$(IntersectRepoPath)\assets\sharingan.bmp»>

7.-En Intersect-Engine\Intersect.Client.Framework\Intersect.Client.Framework.nuspec\
<icon>assets\sharingan.png
<file src=»..\assets\sharingan.png» target=»assets» />

8.-En \Intersect-Engine\Intersect.Editor\Core\Program.cs
private const string IconManifestResourceName = «Intersect.Editor.sharingan.ico»;

9.-En \Intersect-Engine\Intersect.Server.Framework\Intersect.Server.Framework.nuspec
<icon>assets\sharingan.png
<file src=»..\assets\sharingan.png» target=»assets» />

10.-En \Intersect-Engine\Intersect.SinglePlayer\Intersect.SinglePlayer.csproj
<EmbeddedResource Include=»$(IntersectRepoPath)\assets\sharingan.bmp»>

Nombre en la ventana del juego

1.-\Intersect-Engine\Framework\Intersect.Framework.Core\Config\Options.cs
public const string DefaultGameName = «Intersect»;

2.-\Intersect-Engine\Intersect.Client.Core\Localization\Strings.cs

public static LocalizedString GameName = @»Intersect»;

Nota:
si el archivo config.json y client_strings.json ya existe en la carpeta de salida /Resources/, no se sobreescribe automáticamente, se deberá eliminar manualmente client_strings.json y ejecutar:
dotnet clean
dotnet build -p:Configuration=Debug -p:PackageVersion=0.8.0-beta -p:Version=0.8.0 

Este fue el resultado de la modificación:

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *