Die Community zu .NET und Classic VB.
Menü

Normaler 2D-Text

 von 

Einführung  

Dieses Kapitel ist kein kompliziertes, aber Sie werden früher oder später lernen, wie man Text auf den Bildschirm zeichnet - also machen wir das bevor wir mit den etwas fortgeschritteneren Kapitel weitermachen. Text zeichnen ist Text zeichnen und braucht wirklich nicht viel Erklärung oder Theoriearbeit - so können wir gleich damit anfangen.

Normaler 2D-Text  

Diese Methode ist wirklich einfach und Sie werden sie wohl am Meisten benutzen. Fast alle meiner DirectX-Programme haben eine kleine Framerateanzeige in der oberen Ecke. In DirectX7, zeichne ich den Text einfach in die dahin wo ich ihn haben will auf den Backbuffer; jetzt schauen wir uns mal an, wie sich das in DirectX8 geändert hat.

Die gute Sache ist, das, in meiner Meinung, sich das Textzeichnen zum Besseren geändert hat. Sie können Direct3D befehlen ein paar einfache Textmanipulationen(wie zentrieren) mit ihrem Text anzustellen, was Sie in DirectX7 manuell machen mussten. Es ist ein bisschen umständlicher geworden, es ist aber immer noch extrem einfach:

  'Ein paar Variablen, die wir brauchen
Dim MainFont As D3DXFont
  'Das erstellen wir gleich
Dim MainFontDesc As IFont
  'Wir benutzen diese temporäre um den Text zu erstellen
Dim TextRect As RECT
  'Das definiert, wo der Text auftauchen wird
Dim fnt As New StdFont
  'Dieses Objekt wird auch dazu benutzt,
  'um den Text zu definieren

Dim TextToDraw As String
  'Der Text, der gezeichnet wird.

Nicht schwer, nur ein paar Variablen.

  '## TEXT RENDERN INITIALISIEREN ##
fnt.Name = "Verdana"
fnt.Size = 18
fnt.Bold = True

Set MainFontDesc = fntSet
MainFont = D3DX.CreateFont(D3DDevice, MainFontDesc.hFont)

Ein bisschen kompliziert und ein bisschen verrückt, aber das ist, wie mans macht - zuerst füllen wir unser fnt-Objekt mit dem wichtigen Details und bringen dann VB dazu es in unsere IFont-Variable umzuwandeln, welche dann benutzt wird um die Schrift zu erzeugen.

TextRect.Top = 1
TextRect.Left = 1
TextRect.bottom = 32
TextRect.Right = 640
D3DX.DrawText MainFont, &HFFCCCCFF, _
  "Current Frame Rate: " & FPS_Current, TextRect, _
  DT_TOP Or DT_CENTER

Dieser Teil kommt zwischen den "D3Ddevice.BeginScene" und den "D3DDevice.EndScene" in der Renderprozedur. Es ist nicht groß schwer, aber es gibt wieder ein bisschen mehr über das wir vorher nachdenken müsen...

Zuerst ist da das Rechteck - es ist zwar (fast) egal, wenn Sie die falsche Größe erwischen, aber es kann blöd aussehen, wenn es zu klein ist(Text geht verloren), wenn es zu groß ist, verschwenden Sie Resourcen.

Zweitens sind da die Flags; diese können eine Kombination aus diesen Parametern sein:

DT_LEFT Der Text erscheint am linken Rand des Rechtecks(Linksbündig)
DT_TOP Der Text erscheint am oberen Rand des Rechtecks
DT_CENTER Der Text wird horizontal zentriert.
DT_RIGHT Der Text erscheint am rechten Rand des Rechtecks(Rechtbündig)
DT_VCENTER Der Text wird vertikal zentriert.
DT_BOTTOM Der Text taucht am unteren Ende des Rechtecks auf.
DT_SINGLELINE Der Text wird als eine Zeile gezeichnet - Zeilenumbrüche werden ignoriert

Da ist wirklich nicht mehr als das; es gibt zwar noch ein paar mehr Flags, aber die obigen sollten genügen - wenn nicht, dann können Sie ja noch einige andere im VB-Objektbrowser anschauen.

Text aus Bildern  

Diese sind ein bisschen schwerer als die andere Methode, aber wenn sie richtig gemacht können sie auch viel schöner aussehen. Wie Sie gemerkt haben werden, benutzt das obere Beispiel Schriften, die vom System registriert sind - die selben, die Sie in ihrem Grafikprogramm oder Office benutzen. Aber wenn Sie etwas mehr Interessanteres machen wollen, eine Schrift mit Schatten oder 3D-Effekt.

Das ist der Punkt, an dem Sie benutzerdefinierte Schriften benutzen können - ihre Schriften kann alles sein, was durch eine Textur dargestellt werden kann - sei das eine verrückte Alienschrift, oder eine Schrift, die einfach zum Thema des Spiel passt. Der einzige schwierige Teil ist das Malen der Textur, aber wenn sie ein einigermaßenguter Künstler sind, sollte das auch nicht zum Hindernis werden.

Die Grundlage der Fontrasterer ist einfach den String zu nehmen, herauszubekommen, welche Teile der Textur wir brauchen und dann die Geometrie für zu erstellen. Denken Sie sich die Textur als Palette - in der jedes n*n Segment einen Buchstaben enthält - Sie müssen nur herausberechnen, welcher Teil der Textur welchen Buchstaben enthält. Hier ein Beispiel, wie die Textur für unsere Textur aussehen könnte.


Abbildung 1: Vorlage für eine Schriftart

Die grüne Farbe wird später einmal transparent sein.
Jedes Zeichen ist 16x16 Pixel groß; auf einer 256x128-Pixel-Textur erlaubt das 128 Zeichen. Eine 256x256-Pixel große Textur hätte uns 256 Zeichen erlaubt, so viel wie auch im Asciizeichensatz sind; es ist aber unwahrscheinlich, dass Sie je soviel brauchen werden.

Um herauszuarbeiten, welchen Buchstaben wir brauchen benutzen wir einfach die in VB eingebauten Funktionen "mid()" und "Asc()". Der Code sieht so aus:

'Diese Funktion muss zwischen BeginScene
' und EndScene aufgerufen werden.

Private Sub RenderStringFromCustomFont_2D( _
  strText As String, startX As Single,  _
  StartY As Single, Height As Integer,  _
  Width As Integer)

Dim I As Integer
 'Schleifenvariable
Dim CharX As Integer, CharY As Integer
  'Koordinaten unserer Zeichen
Dim Char As String
  'Das aktuelle Zeichen im String
Dim LinearEntry As Integer
  'Das Zeichen als ob die Textur eine Zeile wäre.
  'Leichter so in 2D umzurechnen als direkt.

If Len(strText) = 0 Then Exit Sub
  'Wenn kein Text da ist

For I = 1 To Len(strText)
  'Durch alle Zeichen gehen
  '1.) Texturkoordinaten berechnen
  'Ausknobeln, welchen Eintrag wir in der Textur benutzen müssen
  'der Vertexerstellungscode rechnet das dann in 2D um.

    Char = Mid$(strText, I, 1)
      'Das aktuelle Zeichen holen
    If Asc(Char) >= 65 And Asc(Char) <= 90 Then
         'Zeichen von 65 bis 90 sind die Buchstaben A-Z
         'welche wir umrechnen, dass sie die
        'Positionen 0 bis 25 benutzen
       LinearEntry = Asc(Char) - 65
         'So das Eintrag 65 auf 0 in unserer Textur zeigt.
     ElseIf Asc(Char) >= 97 And Asc(Char) <= 122 Then
         'Jetzt die kleinen Buchstaben
       LinearEntry = Asc(Char) - 71
         'Kleine Buchstaben zeigen auf 26-51
     ElseIf Asc(Char) >= 48 And Asc(Char) <= 57 Then
         'Und jetzt die Zahlen auf dem Bereich von 52 bis 62
       LinearEntry = Asc(Char) + 4

        'Zuletzt die Sonderzeichen: Ich habe mich
        'nicht damit gequält dafür eine Formel zu
        'machen. Deshalb bestimmen wir die Positionen so.
      ElseIf Char = " " Then
          'Leerzeichen
         LinearEntry = 63
      ElseIf Char = "." Then
           'Punkt
         LinearEntry = 62
      ElseIf Char = ";" Then
           'Semikolon
         LinearEntry = 66
      ElseIf Char = "/" Then
          'Schrägstrich
        LinearEntry = 64
      ElseIf Char = "," Then
          'und das Komma
        LinearEntry = 65
      End If
      'Jetzt berechnen wir die wirklichen Koordinaten(2D)

    If LinearEntry <= 15 Then
      CharY = 0
      CharX = LinearEntry
    End If
    If LinearEntry >= 16 And LinearEntry <= 31 Then
       CharY = 1
       CharX = LinearEntry - 16
    End If
    If LinearEntry <= 32 And LinearEntry <= 47 Then
      CharY = 2
      CharX = LinearEntry - 32
    End If
    If LinearEntry >= 48 And LinearEntry <= 63 Then
      CharY = 3
      CharX = LinearEntry - 48
    End If
    If LinearEntry >= 64 And LinearEntry <= 79 Then
      CharY = 4
      CharX = LinearEntry - 64
    End If
    'Füllen Sie den Rest aus, wie Sie es brauchen

    '2.) Die Vertexdaten berechnen

    vertChar(0) = CreateTLVertex(startX + (Width * I), _
      StartY, 0, 1, &HFFFFFF, 0, _
      (1 / 16) * CharX, (1 / 8) * CharY)
    vertChar(1) = CreateTLVertex(startX + (Width * I) _
       + Width, StartY, 0, 1, &HFFFFFF, 0, _
      ((1 / 16) * CharX) + (1 / 16), (1 / 8) * CharY)
    vertChar(2) = CreateTLVertex(startX + (Width * I), _
      StartY + Height, 0, 1, &HFFFFFF, 0, _
      (1 / 16) * CharX, ((1 / 8) * CharY) + (1 / 8))
    vertChar(3) = CreateTLVertex(startX + (Width * I) _
      + Width, StartY + Height, 0, 1, &HFFFFFF, 0, _
      ((1 / 16) * CharX) + (1 / 16), _
      ((1 / 8) * CharY) + (1 / 8))

  '3.) Die Verticen rendern
  D3DDevice.SetTexture 0, fntTex
  'Dem Device unsere Textur zuweisen
  D3DDevice.DrawPrimitiveUP D3DPT_TRIANGLESTRIP, _
    2, vertChar(0), Len(vertChar(0))
Next I

End Sub

Der Code erklärt sich fast selbst, aber hier nochmal eine Skizze wie er funktioniert:

  1. Wir nehmen den String
  2. Wir gehen durch den String, um jedes Zeichen zu rendern.
  3. Obwohl jeder Buchstabe eine 2D Koordinate hat berechnen wir die Koordinate erst in 1D - der LinearEntry Wert
  4. Dann konvertieren wir die 1D-Koordinate in 2D
  5. Jetzt erstellen wir die Verticen - wir benutzen jedes mal die selbe vier Verticen. Der Code konvertiert X/Y-Koordinaten in richtige Texturkoordinaten.
  6. Dann rendern wir die Buchstaben auf den Bildschirm. Das ist der Grund, warum die Funktion zwischen D3DDevice.BeginScene und D3DDevice.EndScene aufgerufen werden muss.

Leider hat diese Methode zwei große Nachteile gegenüber der anderen:

  1. Anzahl der Zeichen - Es gibt eine Grenze für Zeichen. Dieser Code kann höchtens 70 oder so Zeichen benutzen.
  2. Alle Formatierungen(Zentrierung, usw.) müssen von Ihnen unternommen werden. Sie können der Funktion nicht einfach DT_CENTER an den Kopf werfen und hoffen, dass der Text richtig erscheint.

Mehr gibt es eigentlich gar nicht über Textzeichnen zu lernen. Es ist unwahrscheinlich, dass Sie je mehr machen wollen als das hier und wenn, dann wird das, was Sie benutzen, den hier vorgestellten Methoden wahrscheinlich sehr ähneln sein.

Beispielprojekt zum Tutorial [20500 Bytes]

Ihre Meinung  

Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.