Гаразд, вам доведеться пробачити мене за те, що я не дав вам конкретного коду XNA, тому що я не знаю на цій платформі, але те, що я вам скажу, має працювати над будь-яким ігровим двигуном, який дозволяє малювати спрайти.
Шрифти - не єдина ваша проблема, тому я збираюся дати вам поради, а потім я відповім на ваше запитання. Завдяки цим двом речам, ви зможете скласти прекрасні стосунки зі своїм дизайнером GUI, і ви обоє зможете дуже щасливо робити ігри.
Перше, що ти збираєшся сісти з дизайнером, і ти попросиш її надати два набори файлів. Перший - це набір прозорих файлів, які складають ваш графічний інтерфейс (оптимально у форматі PSD або DXT). Для кожної кнопки, фіксованої мітки, фону, рамки та текстового поля ви отримаєте один файл (ви також можете виконати атласування текстури, але я б рекомендував це зробити після того, як ви збираєте графічний інтерфейс, а потім налаштовуєте вихідні координати при блиску). На даний момент нестатичний текст повинен бути опущений (я його перегляну пізніше).
Друге, що ви отримаєте - це власне дизайн GUI, на цей раз у форматі Photoshop. Для цього файлу ви попросите свого дизайнера скласти весь дизайн GUI, використовуючи лише ті файли, які вона вам раніше надала.
Потім вона збирається розмістити кожен елемент GUI в окремому шарі, не використовуючи жодних ефектів. Ви збираєтесь сказати їй зробити цей піксель ідеальним, адже місця, де вона збирається все поставити, - це там, де все буде фактично в завершеній грі.
Як тільки ви зрозумієте, що для кожного шару ви натискаєте Ctrl-T, а на панелі інформації (F8) ви візьмете до уваги координати X і Y для кожного елемента. Переконайтеся, що для ваших одиниць встановлено пікселі (Налаштування-> Одиниці та лінійки-> Одиниці). Це пози, які ви будете використовувати під час малювання своїх спрайтів.
Тепер для шрифтів, як ви, очевидно, знаєте зараз, ви не зможете змусити ваші шрифти виглядати точно так само, як ви бачите їх у 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 та створили індексний файл, який повідомляє вам про кожну кодову точку, у якому файлі знаходиться гліф, його місцезнаходження та розміри. Зауважте, що я також поклав два додаткові пікселі, щоб розділити кожен гліф (для отримання подальших ефектів)
Тепер для кожного з цих файлів ви помістите його в Photoshop і зробіть усі потрібні фільтри. Ви можете встановити кольори, межі, тіні, контури та все, що завгодно. Просто переконайтеся, що наслідки не дозволяють гліфам перекриватися. Якщо так, відрегулюйте відстань, повторіть, промийте та повторіть. Збережіть як 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()
що вони обидва використовують різні системи вимірювання, і це може призвести до невідповідностей між вимірюваним гліфом та намальованим, особливо з перекритими гліфами, знайденими в деяких шрифтах. Більше інформації тут .