Ok, dovrai perdonarmi per non averti fornito un codice XNA specifico, perché non sono ben informato su quella piattaforma, ma quello che sto per dirti dovrebbe funzionare su qualsiasi motore di gioco che ti permetta di disegnare sprite.
I caratteri non sono il tuo unico problema, quindi ti darò un consiglio e poi risponderò alla tua domanda. Con queste due cose, dovresti essere in grado di stabilire una relazione amorosa con il tuo progettista di GUI ed entrambi sarai in grado di creare giochi in modo molto felice.
La prima cosa è che ti siederai con il tuo designer e le chiederai di darti due serie di file. Il primo è un insieme di file trasparenti che compongono la tua GUI (in modo ottimale in formato PSD o DXT). Per ogni pulsante, etichetta fissa, sfondo, bordo e casella di testo, otterrai un file (puoi anche fare un atlante delle trame, ma ti consiglio di farlo dopo aver assemblato la tua GUI e quindi regolare le coordinate della fonte quando si esegue il blitting). Il testo non statico dovrebbe essere lasciato fuori a questo punto (lo rivedrò più avanti).
La seconda cosa che otterrai è il vero design della GUI, questa volta in formato Photoshop. Per questo file, chiederai al tuo designer di realizzare l'intero progetto della GUI, usando solo i file che ti ha dato in precedenza.
Quindi inserirà ogni elemento della GUI in un livello separato, senza usare alcun effetto. Le dirai di fare questo pixel perfetto, perché le posizioni in cui metterà tutto, è dove tutto sarà effettivamente nel gioco finalizzato.
Una volta ottenuto questo, per ogni livello, premi Ctrl-T e, nel riquadro Informazioni (F8), prenderai nota delle coordinate X e Y per ciascun elemento. Assicurati che le tue unità siano impostate su pixel (Preferenze-> Unità e righelli-> Unità). Queste sono le posizioni che utilizzerai quando disegnerai i tuoi sprite.
Ora, per i caratteri, come puoi chiaramente sapere ora, non sarai in grado di far apparire i tuoi caratteri esattamente come li vedi in Photoshop usando le API di rendering del testo. Dovrai pre-renderizzare i tuoi glifi, quindi assemblare programmaticamente i tuoi testi. Ci sono molti modi per farlo e menzionerò quello che uso.
La prima cosa è rendere tutti i tuoi glifi in uno o più file. Se ti interessa solo l'inglese, sarà sufficiente una trama per tutti i glifi, ma se vuoi avere un set di caratteri più esteso, puoi usare diversi file. Assicurati solo che tutti i glifi desiderati siano disponibili sul carattere scelto dal tuo designer.
Quindi, per eseguire il rendering dei glifi, puoi utilizzare le funzionalità di System.Drawing
per ottenere le metriche dei caratteri e disegnare i tuoi glifi:
Color clearColor = Color.Transparent;
Color drawColor = Color.White;
Brush brush = new SolidBrush(drawColor);
TextRenderingHint renderingType = TextRenderingHint.AntiAliasGridFit; // Antialias is fine, but be careful with ClearType, which can blergh your renders when you apply effects
StringFormat stringFormat = StringFormat.GenericTypographic;
string fileNameFormat = "helvetica14_{0}.png";
string mapFileFormat = "helvetica14.txt";
string fontName = "Helvetica";
string fontPath = @"c:\windows\fonts\helvetica.ttf";
float fontSize = 14.3f;
int spacing = 2;
Font font = new Font(fontName, fontSize);
int x = 0;
int y = 0;
int width = 1024; // Force a maximum texture size
int height = 1024;
StringBuilder data = new StringBuilder();
int lineHeight = 0;
int currentPage = 1;
var families = Fonts.GetFontFamilies(fontPath);
List<char> codepoints = new List<char>();
HashSet<char> usedCodepoints = new HashSet<char>();
foreach (FontFamily family in families)
{
var typefaces = family.GetTypefaces();
foreach (Typeface typeface in typefaces)
{
GlyphTypeface glyph;
typeface.TryGetGlyphTypeface(out glyph);
foreach (KeyValuePair<int, ushort> kvp in glyph.CharacterToGlyphMap) // Render all available glyps
{
char c = (char)kvp.Key;
if (!usedCodepoints.Contains(c))
{
codepoints.Add(c);
usedCodepoints.Add(c);
}
}
}
}
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bitmap);
g.Clear(clearColor);
g.TextRenderingHint = renderingType;
foreach (char c in codepoints)
{
string thisChar = c.ToString();
Size s = g.MeasureString(thisChar, font); // Use this instead of MeasureText()
if (s.Width > 0)
{
s.Width += (spacing * 2);
s.Height += (spacing * 2);
if (s.Height > lineHeight)
lineHeight = s.Height;
if (x + s.Width >= width)
{
x = 0;
y += lineHeight;
lineHeight = 0;
if (y + s.Height >= height)
{
y = 0;
g.Dispose();
bitmap.Save(string.Format(fileNameFormat, currentPage));
bitmap.Dispose();
bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
g = Graphics.FromImage(bitmap);
g.Clear(clearColor);
g.TextRenderingHint = renderingType;
currentPage++;
}
}
g.DrawString(thisChar, font, brush, new PointF((float)x + spacing, (float)y + spacing), stringFormat);
data.AppendFormat("{0} {1} {2} {3} {4} {5}\n", (int)c, currentPage, x, y, s.Width, s.Height);
x += s.Width;
}
}
g.Dispose();
bitmap.Save(string.Format(fileNameFormat, currentPage));
bitmap.Dispose();
File.WriteAllText(mapFileFormat, data.ToString());
Con questo, hai disegnato glifi bianchi su uno sfondo trasparente su un mucchio di file PNG e hai creato un file indice che ti dice per ogni punto di codice, in quale file si trova il glifo, la sua posizione e dimensioni. Nota che ho anche messo due pixel aggiuntivi per separare ogni glifo (per adattarmi a ulteriori effetti)
Ora, per ognuno di quei file, lo metti in Photoshop e fai tutti i filtri che desideri. Puoi impostare colori, bordi, ombre, contorni e qualsiasi altra cosa tu voglia. Assicurati solo che gli effetti non sovrappongano i glifi. In tal caso, regolare la spaziatura, eseguire nuovamente il rendering, risciacquare e ripetere. Salva come PNG o DXT e, insieme al file indice, inserisci tutto nel tuo progetto.
Il disegno del testo dovrebbe essere molto semplice. Per ogni carattere che vuoi stampare, trova la sua posizione usando l'indice, disegnalo, fai avanzare la posizione e ripeti. Puoi anche regolare spaziatura, crenatura (difficile), spaziatura verticale e persino colorazione. In lua:
function load_font(name)
local font = {}
font.name = name
font.height = 0
font.max_page = 0
font.glyphs = {}
font.pages = {}
font_definition = read_all_text("font/" .. name .. ".txt")
for codepoint, page, x, y, width, height in string.gmatch(font_definition, "(%d+) (%d+) (%d+) (%d+) (%d+) (%d+)") do
local page = tonumber(page)
local height_num = tonumber(height)
if height_num > font.height then
font.height = height_num
end
font.glyphs[tonumber(codepoint)] = { page=tonumber(page), x=tonumber(x), y=tonumber(y), width=tonumber(width), height=height_num }
if font.max_page < page then
font.max_page = page
end
end
for page = 1, font.max_page do
font.pages[page] = load_image("font/" .. name .. "_" .. page .. ".png")
end
return font
end
function draw_text(font, chars, range, initial_x, initial_y, width, color, spacing)
local x = initial_x - spacing
local y = initial_y - spacing
if range == nil then
range = { from=1, to=#chars }
end
for i = 1, range.to do
local char = chars[i]
local glyph = font.glyphs[char]
if char == 10 then -- line break
x = initial_x - spacing
y = y + ((font.height - (spacing * 2)) * 1.4)
elseif glyph == nil then
if unavailable_glyphs[char] == nil then
unavailable_glyphs[char] = true
end
else
if x + glyph.width - spacing > initial_x + width then
x = initial_x - spacing
y = y + ((font.height - (spacing * 2)) * 1.4)
end
if i >= range.from then
draw_sprite(font.pages[glyph.page], x, y, glyph.x, glyph.y, glyph.width, glyph.height, color)
end
x = x + glyph.width - (spacing * 2)
end
end
end
E il gioco è fatto. Ripeti l'operazione per tutti gli altri caratteri (e ottimizza anche le dimensioni)
Modifica : ho modificato il codice da utilizzare Graphics.MeasureString
anziché TextRenderer.MeasureText()
perché entrambi utilizzano sistemi di misurazione diversi e possono causare incoerenze tra il glifo misurato e quello disegnato, in particolare con glifi sporgenti presenti in alcuni caratteri. Maggiori informazioni qui .