Ok, você terá que me perdoar por não fornecer um código XNA específico, porque não conheço essa plataforma, mas o que vou dizer deve funcionar em qualquer mecanismo de jogo que permita desenhar sprites.
Fontes não é o seu único problema, por isso vou dar um conselho e depois responder sua pergunta. Com essas duas coisas, você poderá estabelecer um relacionamento amoroso com seu designer de GUI, e os dois poderão criar jogos muito felizes.
A primeira coisa é que você vai se sentar com seu designer e pedir a ela que lhe forneça dois conjuntos de arquivos. O primeiro é um conjunto de arquivos transparentes que compõem sua GUI (idealmente no formato PSD ou DXT). Para cada botão, rótulo fixo, plano de fundo, borda e caixa de texto, você receberá um arquivo (você também pode fazer atlas de textura, mas eu recomendo que você faça isso depois de montar sua GUI e, em seguida, ajustar as coordenadas de origem ao fazer a blitagem). O texto não estático deve ser deixado de fora neste momento (revisitarei isso mais tarde).
A segunda coisa que você terá é o design da GUI, desta vez no formato Photoshop. Para esse arquivo, você solicitará ao seu designer que faça o design completo da GUI, usando apenas os arquivos que ele forneceu anteriormente.
Ela então colocará cada elemento da GUI em uma camada separada, sem nenhum efeito. Você vai dizer para ela fazer esse pixel perfeito, porque os locais onde ela colocará tudo é onde tudo estará realmente no jogo finalizado.
Quando você conseguir isso, para cada camada, pressione Ctrl-T e, no painel Informações (F8), você anotará as coordenadas X e Y de cada elemento. Verifique se suas unidades estão definidas para pixels (Preferências-> Unidades e réguas-> Unidades). Essas são as posições que você usará ao desenhar seus sprites.
Agora, para fontes, como você deve saber claramente agora, não será possível fazer com que suas fontes sejam exatamente da mesma maneira que as vê no Photoshop usando APIs de renderização de texto. Você precisará pré-renderizar seus glifos e depois montar programaticamente seus textos. Existem muitas maneiras de fazer isso, e mencionarei a que uso.
A primeira coisa é renderizar todos os seus glifos em um ou mais arquivos. Se você se preocupa apenas com o inglês, uma textura para todos os glifos será suficiente, mas se quiser ter um conjunto de caracteres mais extenso, poderá usar vários arquivos. Apenas verifique se todos os glifos que você deseja estão disponíveis na fonte escolhida pelo designer.
Portanto, para renderizar os glifos, você pode usar os recursos de System.Drawing
para obter as métricas de fonte e desenhar seus glifos:
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());
Com isso, você desenhou glifos brancos sobre um fundo transparente em vários arquivos PNG e criou um arquivo de índice que informa sobre cada ponto de código, em qual arquivo o glifo está localizado, sua localização e dimensões. Observe que eu também coloquei dois pixels adicionais para separar cada glifo (para acomodar outros efeitos)
Agora, para cada um desses arquivos, você o coloca no photoshop e faz todos os filtros que deseja. Você pode definir cores, bordas, sombras, contornos e qualquer outra coisa que desejar. Apenas verifique se os efeitos não fazem os glifos se sobreporem. Nesse caso, ajuste o espaçamento, renderize novamente, enxágue e repita. Salve como PNG ou DXT e, junto com o arquivo de índice, coloque tudo no seu projeto.
O texto do desenho deve ser muito simples. Para cada caractere que você deseja imprimir, encontre sua localização usando o índice, desenhe-o, avance a posição e repita. Você também pode ajustar o espaçamento, kerning (complicado), espaçamento vertical e até coloração. Em 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 lá vai você. Repita o procedimento para todas as outras fontes (e também o tamanho ideal)
Editar : eu mudei o código para usar em Graphics.MeasureString
vez de, TextRenderer.MeasureText()
porque ambos usam sistemas de medição diferentes e podem levar a inconsistências entre o glifo medido e o desenhado, especialmente com glifos pendentes encontrados em algumas fontes. Mais informações aqui .