Хорошо, вам придется простить меня за то, что я не предоставил вам конкретный код XNA, потому что я не разбираюсь в этой платформе, но то, что я собираюсь сказать, должно работать на любом игровом движке, который позволяет рисовать спрайты.
Шрифты - не единственная ваша проблема, поэтому я дам вам совет, а затем я отвечу на ваш вопрос. С этими двумя вещами вы сможете установить дружеские отношения с вашим дизайнером GUI, и вы оба сможете очень счастливо делать игры.
Первое, что вы собираетесь сесть со своим дизайнером, и вы попросите ее дать вам два набора файлов. Первый - это набор прозрачных файлов, которые составляют ваш графический интерфейс (оптимально в формате PSD или DXT). Для каждой кнопки, фиксированной метки, фона, рамки и текстового поля вы получите один файл (вы также можете выполнять наложение текстур, но я бы порекомендовал вам сделать это после того, как вы соберете свой графический интерфейс, а затем откорректируете исходные координаты при блиттинге). Нестатический текст должен быть опущен в этот момент (я вернусь к этому позже).
Второе, что вы получите, это фактический дизайн графического интерфейса, на этот раз в формате Photoshop. Для этого файла вы попросите своего дизайнера сделать весь дизайн графического интерфейса, используя только те файлы, которые она вам ранее предоставила.
Затем она собирается поместить каждый элемент графического интерфейса в отдельный слой, без каких-либо эффектов. Вы скажете ей сделать этот пиксель идеальным, потому что места, где она собирается все поместить, это то, где все будет на самом деле в финальной игре.
Как только вы получите это, для каждого слоя вы нажмете Ctrl-T, и на информационной панели (F8) вы запомните координаты X и Y для каждого элемента. Убедитесь, что ваши единицы установлены в пикселях (Preferences-> Units & Rulers-> Units). Это позиции, которые вы собираетесь использовать при рисовании своих спрайтов.
Теперь, что касается шрифтов, как вы, наверное, уже сейчас знаете, вы не сможете заставить свои шрифты выглядеть точно так же, как вы видите их в Photoshop с помощью API для рендеринга текста. Вам придется предварительно визуализировать ваши глифы, а затем программно собрать ваши тексты. Есть много способов сделать это, и я упомяну тот, который я использую.
Первым делом нужно перевести все ваши глифы в один или несколько файлов. Если вы заботитесь только об английском языке, достаточно одной текстуры для всех глифов, но если вы хотите иметь более расширенный набор символов, вы можете использовать несколько файлов. Просто убедитесь, что все нужные вам символы доступны на шрифте, выбранном вашим дизайнером.
Таким образом, для рендеринга глифов вы можете использовать средства System.Drawing
для получения метрик шрифта и рисования ваших глифов:
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());
При этом вы нарисовали белые глифы на прозрачном фоне на куче файлов PNG и создали индексный файл, который сообщает вам для каждой кодовой точки, в каком файле находится глиф, его местоположение и размеры. Обратите внимание, что я также поместил два дополнительных пикселя, чтобы отделить каждый глиф (чтобы обеспечить дальнейшие эффекты)
Теперь для каждого из этих файлов вы помещаете его в фотошоп и выполняете все необходимые фильтры. Вы можете установить цвета, границы, тени, контуры и все, что вы хотите. Просто убедитесь, что эффекты не перекрывают глифы. Если это так, отрегулируйте интервал, выполните повторную визуализацию, промойте и повторите. Сохраните как PNG или DXT и вместе с индексным файлом поместите все в свой проект.
Рисование текста должно быть очень простым. Для каждого символа, который вы хотите распечатать, найдите его местоположение с помощью индекса, нарисуйте его, продвиньте позицию и повторите. Вы также можете настроить интервал, кернинг (хитрый), вертикальный интервал и даже цвет. В луа:
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
И вот, пожалуйста. Повторите для каждого другого шрифта (и оптимального размера)
Изменить : я изменил код, чтобы использовать Graphics.MeasureString
вместо, TextRenderer.MeasureText()
потому что они оба используют разные системы измерения, и может привести к несоответствиям между измеренным глифом и нарисованным, особенно с нависающими глифами, найденными в некоторых шрифтах. Больше информации здесь .