Được rồi, bạn sẽ phải tha thứ cho tôi vì đã không cung cấp cho bạn mã XNA cụ thể, bởi vì tôi không am hiểu về nền tảng đó, nhưng những gì tôi sẽ nói với bạn là nên làm việc trên bất kỳ công cụ trò chơi nào cho phép bạn vẽ các họa tiết.
Phông chữ không phải là vấn đề duy nhất của bạn, vì vậy tôi sẽ cho bạn một lời khuyên, và sau đó tôi sẽ trả lời câu hỏi của bạn. Với hai điều này, bạn sẽ có thể tạo mối quan hệ yêu đương với nhà thiết kế GUI của mình và cả hai bạn sẽ có thể rất vui vẻ làm trò chơi.
Điều đầu tiên là bạn sẽ ngồi lại với nhà thiết kế của mình và bạn sẽ yêu cầu cô ấy đưa cho bạn hai bộ hồ sơ. Đầu tiên là một tập hợp các tệp trong suốt tạo nên GUI của bạn (tối ưu ở định dạng PSD hoặc DXT). Đối với mỗi nút, nhãn cố định, nền, đường viền và hộp văn bản, bạn sẽ nhận được một tệp (bạn cũng có thể thực hiện kết cấu, nhưng tôi khuyên bạn nên làm điều đó sau khi lắp ráp GUI và sau đó điều chỉnh tọa độ nguồn khi tắt). Văn bản không tĩnh nên được bỏ qua tại thời điểm này (Tôi sẽ xem lại điều này sau).
Điều thứ hai bạn sẽ nhận được là thiết kế GUI thực tế, lần này là ở định dạng Photoshop. Đối với tệp này, bạn sẽ yêu cầu nhà thiết kế của bạn thực hiện toàn bộ thiết kế GUI, chỉ sử dụng các tệp mà trước đây cô ấy đã cung cấp cho bạn.
Sau đó, cô ấy sẽ đặt từng thành phần GUI vào một lớp riêng biệt, không sử dụng bất kỳ hiệu ứng nào. Bạn sẽ bảo cô ấy làm pixel này thật hoàn hảo, bởi vì những vị trí mà cô ấy sẽ đặt mọi thứ, là nơi mọi thứ sẽ thực sự có trong trò chơi hoàn thiện.
Khi bạn nhận được điều đó, với mỗi lớp, bạn sẽ nhấn Ctrl-T và trên ngăn Thông tin (F8), bạn sẽ lưu ý đến tọa độ X và Y cho từng thành phần. Đảm bảo các đơn vị của bạn được đặt thành pixel (Tùy chọn-> Đơn vị & Thước đo-> Đơn vị). Đây là những vị trí bạn sẽ sử dụng khi vẽ các họa tiết của mình.
Bây giờ, đối với các phông chữ, như bạn có thể biết rõ bây giờ, bạn sẽ không thể có được các phông chữ của mình trông giống hệt như cách bạn nhìn thấy chúng trong Photoshop bằng API kết xuất văn bản. Bạn sẽ phải kết xuất trước glyphs của mình và sau đó lập trình các văn bản của bạn theo chương trình. Có nhiều cách để làm điều này, và tôi sẽ đề cập đến cách tôi sử dụng.
Điều đầu tiên là kết xuất tất cả các glyph của bạn thành một hoặc nhiều tệp. Nếu bạn chỉ quan tâm đến tiếng Anh, một kết cấu cho tất cả các glyph sẽ đủ, nhưng nếu bạn muốn có một bộ ký tự mở rộng hơn, bạn có thể sử dụng một số tệp. Chỉ cần đảm bảo rằng tất cả các glyphs bạn muốn có sẵn trên phông chữ mà nhà thiết kế của bạn đã chọn.
Vì vậy, để hiển thị glyphs, bạn có thể sử dụng các phương tiện System.Drawing
để lấy số liệu phông chữ và vẽ glyphs của mình:
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());
Với điều này, bạn đã vẽ các glyph trắng trên nền trong suốt trên một loạt các tệp PNG và tạo một tệp chỉ mục cho bạn biết từng loại tiền mã hóa, trong đó tệp glyph được đặt, vị trí và kích thước của nó. Lưu ý rằng tôi cũng đặt hai pixel bổ sung để tách từng glyph (để đệm cho các hiệu ứng tiếp theo)
Bây giờ, đối với mỗi tệp đó, bạn đặt nó vào photoshop và thực hiện tất cả các bộ lọc bạn muốn. Bạn có thể đặt màu sắc, đường viền, bóng, đường viền và bất cứ thứ gì bạn muốn. Chỉ cần đảm bảo rằng các hiệu ứng không làm cho glyphs trùng nhau. Nếu vậy, điều chỉnh khoảng cách, kết xuất lại, rửa và lặp lại. Lưu dưới dạng PNG hoặc DXT và cùng với tệp chỉ mục, đặt mọi thứ vào dự án của bạn.
Vẽ văn bản nên rất đơn giản. Đối với mỗi char bạn muốn in, tìm vị trí của nó bằng chỉ mục, vẽ nó, tiến vị trí và lặp lại. Bạn cũng có thể điều chỉnh khoảng cách, k sâu (khéo léo), khoảng cách dọc và thậm chí tô màu. Trong 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
Và ở đó bạn đi. Lặp lại cho mọi phông chữ khác (và kích thước tối ưu là tốt)
Chỉnh sửa : Tôi đã thay đổi mã để sử dụng Graphics.MeasureString
thay TextRenderer.MeasureText()
vì cả hai đều sử dụng các hệ thống đo lường khác nhau và có thể dẫn đến sự không thống nhất giữa glyph đo được và mã được vẽ, đặc biệt là với glyphs nhô ra trong một số phông chữ. Thêm thông tin ở đây .