D'accord, vous devrez me pardonner de ne pas vous avoir donné de code XNA spécifique, car je ne connais pas cette plate-forme, mais ce que je vais vous dire devrait fonctionner sur n'importe quel moteur de jeu qui vous permet de dessiner des sprites.
Les polices ne sont pas votre seul problème, je vais donc vous donner un conseil, puis je vais répondre à votre question. Avec ces deux choses, vous devriez être en mesure de faire une relation amoureuse-colombe avec votre concepteur d'interface graphique, et vous pourrez tous deux créer des jeux très heureux.
La première chose est que vous allez vous asseoir avec votre designer, et vous allez lui demander de vous donner deux ensembles de fichiers. Le premier est un ensemble de fichiers transparents qui composent votre interface graphique (de manière optimale au format PSD ou DXT). Pour chaque bouton, étiquette fixe, arrière-plan, bordure et zone de texte, vous obtiendrez un fichier (vous pouvez également faire un atlas de texture, mais je vous recommande de le faire après avoir assemblé votre interface graphique, puis d'ajuster vos coordonnées source lors du blitting). Le texte non statique doit être omis à ce stade (je reviendrai sur ce point plus tard).
La deuxième chose que vous obtiendrez est la conception graphique réelle, cette fois au format Photoshop. Pour ce fichier, vous allez demander à votre concepteur de réaliser l'intégralité de la conception de l'interface graphique, en utilisant uniquement les fichiers qu'elle vous a précédemment fournis.
Elle va ensuite mettre chaque élément GUI dans une couche distincte, sans aucun effet. Vous allez lui dire de faire ce pixel parfait, car les endroits où elle va tout mettre, c'est où tout sera réellement dans le jeu finalisé.
Une fois que vous obtenez cela, pour chaque couche, vous allez appuyer sur Ctrl-T, et dans le volet Info (F8), vous prendrez note des coordonnées X et Y pour chaque élément. Assurez-vous que vos unités sont définies en pixels (Préférences-> Unités et règles-> Unités). Ce sont les positions que vous allez utiliser pour dessiner vos sprites.
Maintenant, pour les polices, comme vous le savez clairement maintenant, vous ne pourrez pas obtenir que vos polices aient exactement le même aspect que vous les voyez dans Photoshop à l'aide des API de rendu de texte. Vous devrez pré-rendre vos glyphes, puis assembler par programme vos textes. Il existe de nombreuses façons de procéder, et je mentionnerai celle que j'utilise.
La première chose à faire est de rendre tous vos glyphes dans un ou plusieurs fichiers. Si vous ne vous souciez que de l'anglais, une seule texture pour tous les glyphes suffira, mais si vous voulez avoir un jeu de caractères plus étendu, vous pouvez utiliser plusieurs fichiers. Assurez-vous simplement que tous les glyphes que vous voulez sont disponibles sur la police choisie par votre designer.
Ainsi, pour rendre les glyphes, vous pouvez utiliser les fonctionnalités de System.Drawing
pour obtenir les mesures de police et dessiner vos glyphes:
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());
Avec cela, vous avez dessiné des glyphes blancs sur un fond transparent sur un tas de fichiers PNG et créé un fichier d'index qui vous indique pour chaque point de code, dans quel fichier se trouve le glyphe, son emplacement et ses dimensions. Notez que j'ai également mis deux pixels supplémentaires pour séparer chaque glyphe (pour accueillir d'autres effets)
Maintenant, pour chacun de ces fichiers, vous le mettez dans photoshop et effectuez tous les filtres que vous souhaitez. Vous pouvez définir les couleurs, les bordures, les ombres, les contours et tout ce que vous voulez. Assurez-vous simplement que les effets ne font pas chevaucher les glyphes. Si c'est le cas, ajustez l'espacement, restituez, rincez et répétez. Enregistrez au format PNG ou DXT, et avec le fichier d'index, mettez tout dans votre projet.
Le texte de dessin doit être très simple. Pour chaque caractère que vous souhaitez imprimer, recherchez son emplacement à l'aide de l'index, dessinez-le, avancez la position et répétez. Vous pouvez également ajuster l'espacement, le crénage (délicat), l'espacement vertical et même la coloration. À 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
Et voilà. Répétez l'opération pour toutes les autres polices (et la taille optimale également)
Edit : j'ai changé le code à utiliser Graphics.MeasureString
au lieu de TextRenderer.MeasureText()
car ils utilisent tous deux des systèmes de mesure différents, et peut entraîner des incohérences entre le glyphe mesuré et celui dessiné, en particulier avec les glyphes en surplomb trouvés dans certaines polices. Plus d'informations ici .