Okay, Sie werden mir verzeihen müssen, dass ich Ihnen keinen speziellen XNA-Code gegeben habe, da ich mich mit dieser Plattform nicht auskenne, aber was ich Ihnen sagen werde, sollte mit jeder Spiel-Engine funktionieren, mit der Sie Sprites zeichnen können.
Schriftarten sind nicht Ihr einziges Problem. Ich gebe Ihnen daher einen Rat und beantworte dann Ihre Frage. Mit diesen beiden Dingen sollten Sie in der Lage sein, eine Liebesbeziehung zu Ihrem GUI-Designer herzustellen, und Sie werden beide in der Lage sein, sehr glücklich Spiele zu machen.
Das erste ist, dass Sie sich mit Ihrem Designer zusammensetzen und sie bitten, Ihnen zwei Sätze von Dateien zu geben. Das erste ist eine Reihe transparenter Dateien, aus denen sich Ihre Benutzeroberfläche zusammensetzt (optimalerweise im PSD- oder DXT-Format). Für jede Schaltfläche, jedes feste Etikett, jeden Hintergrund, jeden Rahmen und jedes Textfeld erhalten Sie eine Datei (Sie können auch Texturatlas erstellen, ich empfehle dies jedoch, nachdem Sie Ihre GUI zusammengestellt und dann Ihre Quellkoordinaten beim Blitten angepasst haben). Nicht statischer Text sollte an dieser Stelle weggelassen werden (ich werde dies später noch einmal überprüfen).
Als zweites erhalten Sie das eigentliche GUI-Design, diesmal im Photoshop-Format. Für diese Datei werden Sie Ihren Designer bitten, das gesamte GUI-Design zu erstellen , wobei nur die Dateien verwendet werden, die Sie zuvor erhalten haben.
Sie wird dann jedes GUI-Element in eine separate Ebene legen und dabei keinerlei Effekte verwenden. Du wirst ihr sagen, dass sie dieses Pixel perfekt machen soll, denn die Orte, an denen sie alles ablegen wird, sind die Orte, an denen sich alles im endgültigen Spiel befinden wird.
Sobald Sie dies erhalten haben, drücken Sie für jede Ebene die Tastenkombination Strg-T und notieren im Infofenster (F8) die X- und Y-Koordinaten für jedes Element. Stellen Sie sicher, dass Ihre Einheiten auf Pixel eingestellt sind (Einstellungen-> Einheiten & Lineale-> Einheiten). Dies sind die Positionen, die Sie beim Zeichnen Ihrer Sprites verwenden werden.
Wie Sie jetzt sicher wissen, können Sie bei Schriftarten nicht erreichen, dass Ihre Schriftarten genau so aussehen, wie Sie sie in Photoshop mithilfe von Text-Rendering-APIs sehen. Sie müssen Ihre Glyphen vorrendern und dann programmatisch Ihre Texte zusammenstellen. Es gibt viele Möglichkeiten, dies zu tun, und ich werde die erwähnen, die ich benutze.
Als erstes rendern Sie alle Ihre Glyphen in eine oder mehrere Dateien. Wenn Sie sich nur für Englisch interessieren, reicht eine Textur für alle Glyphen aus. Wenn Sie jedoch einen erweiterten Zeichensatz möchten, können Sie mehrere Dateien verwenden. Stellen Sie einfach sicher, dass alle gewünschten Glyphen für die von Ihrem Designer gewählte Schriftart verfügbar sind.
System.Drawing
Um die Glyphen zu rendern, können Sie die Funktionen von verwenden , um die Schriftartmetriken abzurufen und Ihre Glyphen zu zeichnen:
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());
Damit haben Sie weiße Glyphen über einen transparenten Hintergrund in einer Reihe von PNG-Dateien gezeichnet und eine Indexdatei erstellt, die für jeden Codepunkt angibt, in welcher Datei sich die Glyphe befindet, wo sie sich befindet und welche Abmessungen sie haben. Beachten Sie, dass ich auch zwei zusätzliche Pixel anbringe, um die einzelnen Glyphen zu trennen (um weitere Effekte zu erzielen).
Nun legen Sie jede dieser Dateien in Photoshop ab und führen alle gewünschten Filter aus. Sie können Farben, Ränder, Schatten, Konturen und alles andere festlegen, was Sie möchten. Stellen Sie einfach sicher, dass sich die Glyphen durch die Effekte nicht überlappen. Passen Sie in diesem Fall den Abstand an, rendern Sie erneut, spülen Sie und wiederholen Sie den Vorgang. Speichern Sie als PNG oder DXT und fügen Sie zusammen mit der Indexdatei alles in Ihr Projekt ein.
Zeichentext sollte sehr einfach sein. Suchen Sie für jedes Zeichen, das Sie drucken möchten, die Position anhand des Index, zeichnen Sie es, verschieben Sie die Position und wiederholen Sie den Vorgang. Sie können auch den Abstand, das Kerning (tricky), den vertikalen Abstand und sogar die Farbe anpassen. 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
Und los geht's. Wiederholen Sie diesen Vorgang für jede andere Schriftart (und auch für die optimale Größe).
Bearbeiten : Ich änderte den Code zu verwenden , Graphics.MeasureString
statt , TextRenderer.MeasureText()
weil sie beiden unterschiedlichen Messsysteme verwenden, und kann zu Inkonsistenzen zwischen der gemessenen Glyphe führen und der gezogene ein, insbesondere mit überhängenden Glyphen in einigen Schriftart gefunden. Mehr Infos hier .