Modelli di interfaccia utente per il codice


17

Il mio designer dell'interfaccia utente ha realizzato un adorabile PSD Photoshop dell'interfaccia utente e tutto è carino. Il problema più grande che sto riscontrando è la conversione di alcuni dei caratteri più eleganti utilizzati in qualcosa di renderizzabile nel gioco. C'è un modo per convertire questi stili di carattere in Photoshop in un carattere bitmap di qualche tipo?

Devo essere in grado di visualizzare il testo in questo modo nel mio codice:

inserisci qui la descrizione dell'immagine



Grazie mille per la generosità, ma ho notato che non l'hai contrassegnato come risposta accettata. Sei insoddisfatto della risposta? Ti aspettavi un diverso tipo di risposta? Metto insieme le GUI di gioco come parte del mio lavoro quotidiano, quindi penso che potrei essere in grado di rispondere alle tue domande. Sentiti libero di chiedere chiarimenti o spiegazioni più approfondite se ne hai bisogno.
Panda Pajama,

Solo una svista da parte mia. :) L'ho corretto ora. Divertiti e grazie!
Vaughan Hilts,

Risposte:


18

Ok, dovrai perdonarmi per non averti fornito un codice XNA specifico, perché non sono ben informato su quella piattaforma, ma quello che sto per dirti dovrebbe funzionare su qualsiasi motore di gioco che ti permetta di disegnare sprite.

I caratteri non sono il tuo unico problema, quindi ti darò un consiglio e poi risponderò alla tua domanda. Con queste due cose, dovresti essere in grado di stabilire una relazione amorosa con il tuo progettista di GUI ed entrambi sarai in grado di creare giochi in modo molto felice.

La prima cosa è che ti siederai con il tuo designer e le chiederai di darti due serie di file. Il primo è un insieme di file trasparenti che compongono la tua GUI (in modo ottimale in formato PSD o DXT). Per ogni pulsante, etichetta fissa, sfondo, bordo e casella di testo, otterrai un file (puoi anche fare un atlante delle trame, ma ti consiglio di farlo dopo aver assemblato la tua GUI e quindi regolare le coordinate della fonte quando si esegue il blitting). Il testo non statico dovrebbe essere lasciato fuori a questo punto (lo rivedrò più avanti).

La seconda cosa che otterrai è il vero design della GUI, questa volta in formato Photoshop. Per questo file, chiederai al tuo designer di realizzare l'intero progetto della GUI, usando solo i file che ti ha dato in precedenza.

Quindi inserirà ogni elemento della GUI in un livello separato, senza usare alcun effetto. Le dirai di fare questo pixel perfetto, perché le posizioni in cui metterà tutto, è dove tutto sarà effettivamente nel gioco finalizzato.

Una volta ottenuto questo, per ogni livello, premi Ctrl-T e, nel riquadro Informazioni (F8), prenderai nota delle coordinate X e Y per ciascun elemento. Assicurati che le tue unità siano impostate su pixel (Preferenze-> Unità e righelli-> Unità). Queste sono le posizioni che utilizzerai quando disegnerai i tuoi sprite.

Ora, per i caratteri, come puoi chiaramente sapere ora, non sarai in grado di far apparire i tuoi caratteri esattamente come li vedi in Photoshop usando le API di rendering del testo. Dovrai pre-renderizzare i tuoi glifi, quindi assemblare programmaticamente i tuoi testi. Ci sono molti modi per farlo e menzionerò quello che uso.

La prima cosa è rendere tutti i tuoi glifi in uno o più file. Se ti interessa solo l'inglese, sarà sufficiente una trama per tutti i glifi, ma se vuoi avere un set di caratteri più esteso, puoi usare diversi file. Assicurati solo che tutti i glifi desiderati siano disponibili sul carattere scelto dal tuo designer.

Quindi, per eseguire il rendering dei glifi, puoi utilizzare le funzionalità di System.Drawingper ottenere le metriche dei caratteri e disegnare i tuoi glifi:

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());

Con questo, hai disegnato glifi bianchi su uno sfondo trasparente su un mucchio di file PNG e hai creato un file indice che ti dice per ogni punto di codice, in quale file si trova il glifo, la sua posizione e dimensioni. Nota che ho anche messo due pixel aggiuntivi per separare ogni glifo (per adattarmi a ulteriori effetti)

Ora, per ognuno di quei file, lo metti in Photoshop e fai tutti i filtri che desideri. Puoi impostare colori, bordi, ombre, contorni e qualsiasi altra cosa tu voglia. Assicurati solo che gli effetti non sovrappongano i glifi. In tal caso, regolare la spaziatura, eseguire nuovamente il rendering, risciacquare e ripetere. Salva come PNG o DXT e, insieme al file indice, inserisci tutto nel tuo progetto.

Il disegno del testo dovrebbe essere molto semplice. Per ogni carattere che vuoi stampare, trova la sua posizione usando l'indice, disegnalo, fai avanzare la posizione e ripeti. Puoi anche regolare spaziatura, crenatura (difficile), spaziatura verticale e persino colorazione. 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

E il gioco è fatto. Ripeti l'operazione per tutti gli altri caratteri (e ottimizza anche le dimensioni)

Modifica : ho modificato il codice da utilizzare Graphics.MeasureStringanziché TextRenderer.MeasureText()perché entrambi utilizzano sistemi di misurazione diversi e possono causare incoerenze tra il glifo misurato e quello disegnato, in particolare con glifi sporgenti presenti in alcuni caratteri. Maggiori informazioni qui .


2
Perché ho ottenuto un downvote su questo? Se hai intenzione di sottovalutare, per favore almeno fai alcuni commenti su ciò che ho fatto di sbagliato in modo da poterlo risolvere la prossima volta.
Panda Pajama,

Non me. Questa è un'eccellente risposta approfondita. +1 :-)
Kromster dice che supporta Monica l'

6

Bene, come ha detto qualcun altro, in XNA, spritefont fa il lavoro pesante per te. sul sito del club dei creatori c'è un esportatore di font bitmap che esporta in immagini di font in stile XNA. ( http://xbox.create.msdn.com/en-US/education/catalog/utility/bitmap_font_maker ) Quindi, puoi aprirlo in Photoshop o altro e renderlo carino. Da lì, aggiungi la trama al tuo progetto di contenuto e, nel tipo di contenuto, seleziona la trama del carattere sprite. Nel tuo codice, lo carichi come un normale carattere sprite

(Esempio: http://www.youtube.com/watch?v=SynGWrWYUQI )


Il problema è che non sono esattamente sicuro di come si possano prendere gli stili da un carattere Photoshop e applicarli a una trama come questa.
Vaughan Hilts,

Qui, farò un video
CobaltHex,


BMFont fa la stessa cosa, ma secondo me è un programma migliore. angelcode.com/products/bmfont
Cypher

eh, esportando uno spritefont di base, puoi personalizzarlo come vuoi in Photoshop
CobaltHex

4

La soluzione è abbastanza semplice ed è utilizzata da un gran numero di giochi. Tutto quello che devi fare è trattare i tuoi caratteri come se fossero sprite.

Chiedi al tuo designer di disegnare l'intera gamma di numeri e lettere che desideri utilizzare nel tuo gioco. Quindi esegui il rendering in immagini statiche di dimensioni variabili (.png, .bmp, qualunque sia il formato che usi). Avrai qualcosa del genere:

inserisci qui la descrizione dell'immagine

Ora tutto ciò che devi fare è rendere ogni lettera dal tuo "foglio dei caratteri" come se fosse uno sprite sullo schermo. Sicuramente aiuta a costruire una classe helper da tradurre tra stringhe e sprite.

La mia implementazione è più complessa, ma utile. Il foglio dei caratteri è costruito come l'immagine sopra con più caratteri tutti in un unico file .png. Ho un .inifile che mappa ogni lettera dei caratteri in una posizione sul foglio, insieme alla sua larghezza e altezza. Ciò consente al mio designer (ea me stesso) di impazzire creando font fantastici senza dover toccare alcun codice. Quando disegno una stringa sullo schermo, ho un metodo che cerca il carattere e il charfile .ini per ottenere la posizione e i confini della lettera dal foglio dei caratteri, quindi disegno solo Texture2Dcon SpriteBatch.Draw()l'origine Rectangledella lettera in questione.


2

L'interfaccia utente è un argomento vasto e complesso. Il rendering dei caratteri è una parte difficile. Ti consiglio di utilizzare una libreria già esistente che ti consente di visualizzare contenuti Flash o HTML nel gioco, invece di rifare tutto da soli.

Awesomium sembra promettente e dovrebbe funzionare con XNA , quindi puoi provarlo. È gratuito per i giochi non commerciali o se non stai facendo un sacco di soldi:

Gratuito per le aziende indipendenti
    Se la tua azienda ha guadagnato meno di $ 100.000 l'anno scorso, ti qualifichi!
Gratuito per uso non commerciale
Gratuito per valutazione e sviluppo


È un'idea piuttosto ingegnosa: credo che astragga anche parte del codice dell'interfaccia utente che devo scrivere. Lo proverò. Grazie!
Vaughan Hilts

Poiché è una porta del motore Webkit, dovresti essere in grado di eseguire la maggior parte degli stili di testo di cui hai bisogno con i CSS, inclusi contorni, ombre e gradienti.
ChrisC

questo è molto più complesso per il semplice disegno di caratteri
CobaltHex,

1
@CobaltHex Ho visto questo atteggiamento così tante volte e così tante UI viziate che derivavano da un iniziale "yey facciamo una UI da zero, deve essere facile, reinventeremo la ruota mentre ci siamo" che sono cresciuto Stufo di esso. Come esercizio, controlla l'immagine del modello OP e immagina di dover eseguire il rendering di un'intera interfaccia utente nello stesso stile su più piattaforme, risoluzioni dello schermo e rapporti. Ora la necessità di una corretta interfaccia utente diventa chiara, ecco perché mi sono preso la libertà di pubblicare questa risposta, anche se non è una soluzione diretta al problema dato.
Laurent Couvidou,

Non sto dicendo che crei un'interfaccia utente da zero, ma se vuoi solo disegnare un font, inserire un intero motore di rendering è un po 'eccessivo
CobaltHex,

1

Se stai cercando effetti più elaborati del semplice importatore .spritefont, puoi provare a cercare un "generatore di font bitmap".

Personalmente preferisco questo: http://www.ironstarmedia.co.uk/2010/01/free-game-dev-utility-fancy-bitmap-font-generator/

Alcune altre idee:

  • Utilizzare un generatore di caratteri bitmap e quindi modificare la bitmap che produce ulteriormente in Photoshop, ecc.
  • Inserisci più testo statico possibile negli sprite pre-disegnati. Quindi compila solo cose come gamertag e totalizza punteggi usando .spritefonts o font generati da un generatore di font bitmap.

L'ho visto sicuramente (ed è molto bello, comunque) ma speravo di trasformare direttamente i miei stili di testo di Photoshop in caratteri bitmap utilizzabili.
Vaughan Hilts,

0

XNAfa tutto il duro lavoro per te. Con Spritefontte puoi facilmente convertire un file di font sul tuo computer nel tipo di foglio sprite che stai chiedendo definendo un file XML.

Dopo aver aggiunto il file XML al progetto Content, caricalo con ContentManager:

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

Ecco un esempio di un file .spritefont dal mio progetto di contenuto:

<?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>

1
Il problema è che questi sono solo caratteri TrueType. Ho bisogno di caratteri bitmap o qualcosa del genere con tutto il mio dropshadow, i bagliori e simili ancora applicati.
Vaughan Hilts,

Vedi la mia modifica, i font come questi: i.imgur.com/VaBpQ.png
Vaughan Hilts

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.