Makiety interfejsu użytkownika do kodu

17

Mój projektant interfejsu użytkownika stworzył piękny PSD z interfejsu użytkownika i wszystko ładnie. Największym problemem, jaki mam, jest konwersja niektórych bardziej eleganckich czcionek używanych w coś do renderowania w grze. Czy istnieje sposób na konwersję tych stylów czcionek w Photoshopie na czcionkę bitmapową?

Muszę być w stanie renderować taki tekst wewnątrz mojego kodu:

wprowadź opis zdjęcia tutaj

Vaughan Hilts
źródło
Czy sprawdziłeś takie witryny? blogs.msdn.com/b/garykac/archive/2006/08/30/732007.aspx
ssb
Bardzo dziękuję za nagrodę, ale zauważyłem, że nie zaznaczyłeś jej jako przyjętej odpowiedzi. Czy jesteś niezadowolony z odpowiedzi? Czy spodziewałeś się innego rodzaju odpowiedzi? Składam GUI do gry w ramach mojej codziennej pracy, więc myślę, że mogę być w stanie odpowiedzieć na twoje pytania. W razie potrzeby możesz poprosić o wyjaśnienia lub bardziej szczegółowe wyjaśnienia.
Panda Pajama,
Po prostu niedopatrzenie z mojej strony. :) Poprawiłem to teraz. Ciesz się i dziękuję!
Vaughan Hilts,

Odpowiedzi:

18

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.Drawingpobierania 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.MeasureStringzamiast, 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 .

Panda Piżama
źródło
2
Dlaczego otrzymałem głos w tej sprawie? Jeśli masz zamiar głosować, proszę przynajmniej skomentuj, co zrobiłem źle, abym mógł to naprawić następnym razem.
Panda Pajama,
Nie ja. To doskonała dogłębna odpowiedź. +1 :-)
Kromster mówi o wsparciu Moniki
6

Cóż, jak ktoś inny powiedział w XNA, spritefont wykonuje dla ciebie ciężkie podnoszenie. na stronie klubu twórców znajduje się eksporter czcionek bitmapowych, który eksportuje obrazy czcionek w stylu XNA. ( http://xbox.create.msdn.com/en-US/education/catalog/utility/bitmap_font_maker ) Następnie możesz otworzyć go w Photoshopie lub czymkolwiek i sprawić, by wyglądał ładnie. Następnie dodajesz teksturę do projektu treści, a następnie w typie treści zaznacz teksturę czcionki duszka. W kodzie ładujesz go jak normalną czcionkę sprite

(Przykład: http://www.youtube.com/watch?v=SynGWrWYUQI )

CobaltHex
źródło
Problem w tym, że nie jestem do końca pewien, w jaki sposób można pobrać style z czcionki Photoshop i zastosować je do takiej tekstury.
Vaughan Hilts,
Tutaj zrobię film
CobaltHex,
BMFont robi to samo, ale moim zdaniem jest to lepszy program. angelcode.com/products/bmfont
Cypher
eh, eksportując podstawowy spritefont, możesz go dostosować w
dowolny sposób
4

Rozwiązanie jest dość proste i jest używane przez dużą liczbę gier. Wszystko, co musisz zrobić, to traktować czcionki tak, jakby były sprajtami.

Poproś projektanta, aby narysował cały zakres cyfr i liter, których chcesz użyć w swojej grze. Następnie wyrenderuj je na obrazach statycznych o różnych rozmiarach (.png, .bmp, niezależnie od używanego formatu). Będziesz miał coś takiego:

wprowadź opis zdjęcia tutaj

Teraz wszystko, co musisz zrobić, to wyrenderować każdą literę z „arkusza czcionek” tak, jakby to była duszka na ekranie. Z pewnością pomaga zbudować klasę pomocniczą do tłumaczenia między ciągami znaków i duchami.

Moja implementacja jest bardziej złożona, ale przydatna. Arkusz czcionek jest zbudowany jak na powyższym obrazie z wieloma czcionkami w jednym pliku .png. mam.ini plik, który mapuje literę każdej czcionki na pozycję na arkuszu, wraz z jej szerokością i wysokością. To pozwala mojemu projektantowi (i mnie) szaleć, tworząc fajne czcionki bez konieczności dotykania żadnego kodu. Podczas rysowania ciągu na ekranie mam metodę, która sprawdza czcionkę i charplik .ini, aby uzyskać pozycję i granice litery z arkusza czcionek, a następnie po prostu rysuję Texture2Dza SpriteBatch.Draw()pomocą źródła Rectanglelitery w pytaniu.

Szyfrować
źródło
2

Interfejs użytkownika jest obszernym i złożonym tematem. Renderowanie czcionek jest trudną częścią. Radzę korzystać z już istniejącej biblioteki, która pozwala wyświetlać zawartość Flash lub HTML w grze, zamiast ponawiać wszystko samodzielnie.

Awesomium wygląda obiecująco i powinien współpracować z XNA , więc możesz spróbować. Jest darmowy do użytku w niekomercyjnych grach lub jeśli nie zarabiasz ton pieniędzy:

Bezpłatnie dla firm niezależnych
    Jeśli Twoja firma zarobiła w zeszłym roku mniej niż 100 000 USD, kwalifikujesz się!
Darmowy do użytku niekomercyjnego
Darmowy do oceny i rozwoju

Laurent Couvidou
źródło
To całkiem sprytny pomysł - myślę, że streszcza część kodu interfejsu, który też muszę napisać. Dam temu szansę. Dzięki!
Vaughan Hilts
Ponieważ jest to port silnika Webkit, powinieneś być w stanie wykonać większość stylów tekstu, które potrzebujesz w CSS, w tym kontury obrysu, cienie i gradienty.
ChrisC
jest to o wiele bardziej skomplikowane niż proste rysowanie czcionek
CobaltHex,
1
@CobaltHex Widziałem to podejście tyle razy i tyle zepsutego interfejsu użytkownika, który wywodził się z początkowego „tak, zróbmy interfejs od zera, to musi być łatwe, wymyślimy koło, gdy będziemy przy nim”, że dorastałem dość tego. W ramach ćwiczenia sprawdź obraz makiety OP i wyobraź sobie, że musisz wyrenderować cały interfejs użytkownika w tym samym stylu na kilku platformach, rozdzielczościach ekranu i proporcjach. Teraz potrzeba właściwego interfejsu użytkownika staje się jasna, dlatego mogłem opublikować tę odpowiedź, nawet jeśli nie jest to bezpośrednie rozwiązanie danego problemu.
Laurent Couvidou
Nie twierdzę, że tworzysz interfejs od zera, ale jeśli chcesz tylko narysować czcionkę, wstawienie całego silnika renderowania jest nieco przesadzone
CobaltHex,
1

Jeśli szukasz bardziej efektownych efektów niż zwykły importer .spritefont, możesz spróbować wyszukać „generator czcionek bitmapowych”.

Osobiście wolę ten: http://www.ironstarmedia.co.uk/2010/01/free-game-dev-utility-fancy-bitmap-font-generator/

Inne pomysły:

  • Użyj generatora czcionek bitmapowych, a następnie edytuj bitmapę, którą produkuje dalej w Photoshopie itp.
  • Umieść jak najwięcej statycznego tekstu we wstępnie narysowanych duszkach. Następnie wypełnij tylko takie elementy, jak znaczniki gier i zsumuj wyniki, używając .spritefonts lub czcionek wygenerowanych z generatora czcionek bitmapowych.
Nacięcie
źródło
Zdecydowanie to widziałem (a przy okazji jest to bardzo fajne), ale miałem nadzieję, że bezpośrednio zmienią moje style tekstowe Photoshopa na użyteczne czcionki bitmapowe.
Vaughan Hilts
0

XNAwykonuje dla ciebie całą ciężką pracę. Dzięki Spritefontniemu możesz łatwo przekonwertować plik czcionki na komputerze na rodzaj arkusza sprite, o który pytasz, definiując plik XML.

Po dodaniu pliku XML do projektu Content załaduj go ContentManager:

ContentManager.Load<SpriteFont>(@"MyFont");

Oto przykład pliku .spritefont z mojego projektu treści:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">

    <!--
Modify this string to change the font that will be imported.
//TODO: A different font should be chosen before shipping for licensing reasons
-->
    <FontName>Pericles</FontName>

    <!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
    <Size>8.5</Size>

    <!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
    <Spacing>0</Spacing>

    <!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
    <UseKerning>true</UseKerning>

    <!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
    <Style>Bold</Style>

    <!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
    <DefaultCharacter>@</DefaultCharacter>

    <!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
    <CharacterRegions>
        <CharacterRegion>
            <Start>&#32;</Start>
            <End>&#126;</End>
        </CharacterRegion>
        <CharacterRegion>
            <Start>&#9;</Start>
            <End>&#9;</End>
        </CharacterRegion>
    </CharacterRegions>
</Asset>
</XnaContent>
Jim
źródło
1
Problem polega na tym, że są to zwykłe czcionki TrueType. Potrzebuję czcionek bitmapowych lub czegoś podobnego z całym moim cieniem, świecącymi i tym podobnymi nadal stosowanymi.
Vaughan Hilts
Zobacz moją edycję, czcionki takie jak: i.imgur.com/VaBpQ.png
Vaughan Hilts
0

Nie jestem pewien, ponieważ nigdy go nie użyłem, ale ludzie sugerowali mi użycie Glyph Designer. Oto samouczek wideo:

http://vimeo.com/32777161

Tutaj jest dyskusja na temat Photoshopa.

Są też ludzie używający edytora czcionek Hiero .

W tej stronie znajduje się lista innych edytorów czcionek, które możesz chcieć obejrzeć.

Daj mi znać, który z nich jest dla Ciebie najlepszy :)

mm24
źródło