Dobra, musisz mi wybaczyć, że nie podałem ci konkretnego kodu XNA, ponieważ nie mam wiedzy na tej platformie, ale powiem ci, że powinieneś pracować na każdym silniku gry, który pozwala rysować duszki.
Czcionki to nie jedyny problem, więc dam ci radę, a potem odpowiem na twoje pytanie. Dzięki tym dwóm rzeczom powinieneś być w stanie nawiązać miłosną więź ze swoim projektantem GUI, a oboje będziecie mogli bardzo szczęśliwie tworzyć gry.
Pierwszą rzeczą jest to, że usiądziesz ze swoim projektantem i poprosisz ją, aby dała ci dwa zestawy plików. Pierwszy to zestaw przezroczystych plików tworzących GUI (optymalnie w formacie PSD lub DXT). Za każdy przycisk, naprawioną etykietę, tło, ramkę i pole tekstowe otrzymasz jeden plik (możesz także wykonać teksturowanie, ale zalecam to zrobić po złożeniu GUI, a następnie dostosowaniu współrzędnych źródłowych podczas blittingu). W tym miejscu należy pominąć tekst niestatyczny (wrócę później).
Drugą rzeczą, którą dostaniesz, jest faktyczny wygląd GUI, tym razem w formacie Photoshop. W przypadku tego pliku poprosisz swojego projektanta o wykonanie całego projektu GUI, używając tylko plików, które wcześniej ci dała.
Następnie umieści każdy element GUI na osobnej warstwie, nie używając żadnych efektów. Powiesz jej, żeby zrobiła ten piksel perfekcyjnie, ponieważ miejsca, w których wszystko położy, to właśnie tam wszystko znajdzie się w finalnej grze.
Gdy to osiągniesz, dla każdej warstwy naciśniesz Ctrl-T, a na panelu Informacje (F8) zwrócisz uwagę na współrzędne X i Y dla każdego elementu. Upewnij się, że twoje jednostki są ustawione na piksele (Preferencje-> Jednostki i linijki-> Jednostki). Są to pozycje, których będziesz używać podczas rysowania duszków.
Teraz, w przypadku czcionek, jak być może teraz wyraźnie wiesz, nie będziesz w stanie sprawić, aby czcionki wyglądały dokładnie tak samo, jak w Photoshopie przy użyciu interfejsów API renderowania tekstu. Będziesz musiał wstępnie renderować swoje glify, a następnie programowo składać swoje teksty. Jest na to wiele sposobów i wspomnę o tym, którego używam.
Pierwszą rzeczą jest przekształcenie wszystkich glifów w jeden lub więcej plików. Jeśli zależy ci tylko na języku angielskim, wystarczy jedna tekstura dla wszystkich glifów, ale jeśli chcesz mieć bardziej rozbudowany zestaw znaków, możesz użyć kilku plików. Upewnij się tylko, że wszystkie potrzebne glify są dostępne w czcionce wybranej przez projektanta.
Aby renderować glify, możesz użyć funkcji System.Drawing
pobierania metryk czcionek i rysowania glifów:
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());
Dzięki temu narysowałeś białe glify na przezroczystym tle na wiązce plików PNG i utworzyłeś plik indeksu, który informuje cię o każdym punkcie kodowym, w którym pliku znajduje się glif, jego lokalizacji i wymiarach. Zauważ, że umieszczam również dwa dodatkowe piksele, aby oddzielić każdy glif (aby pomieścić w celu uzyskania dalszych efektów)
Teraz dla każdego z tych plików umieść go w Photoshopie i wykonaj wszystkie wymagane filtry. Możesz ustawić kolory, obramowania, cienie, kontury i cokolwiek innego. Upewnij się tylko, że efekty nie powodują nakładania się glifów. Jeśli tak, dostosuj odstępy, ponownie renderuj, spłucz i powtórz. Zapisz jako PNG lub DXT i wraz z plikiem indeksu umieść wszystko w swoim projekcie.
Rysowanie tekstu powinno być bardzo proste. Dla każdego znaku, który chcesz wydrukować, znajdź jego lokalizację za pomocą indeksu, narysuj go, przesuń pozycję i powtórz. Możesz także dostosować odstępy, kerning (trudne), pionowe odstępy, a nawet kolorowanie. W 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
I proszę bardzo. Powtarzaj dla każdej innej czcionki (i optymalnie również rozmiaru)
Edycja : Zmieniłem kod, aby go używał Graphics.MeasureString
zamiast, TextRenderer.MeasureText()
ponieważ oba używają różnych systemów pomiarowych i mogą prowadzić do niespójności między zmierzonym i narysowanym glifem, szczególnie w przypadku przewieszonych glifów występujących w niektórych czcionkach. Więcej informacji tutaj .