Is there a way to center text when drawing using BmFont? I'm using the code from here: Using a BMP image as font in Monogame
The only code change I did was that I added a _TextWidth
int to DrawText
which uses DX - X
to get the text length, then a function GetTextLength
to return it to the button class, which then takes the ((button width - text width) / 2)
to get the starting point of the text, centering it. However, there seems to be some problems and the text doesn't center using its own text width, but using the next button's text width instead. Returning the text width is fine, but for some reason when it draws on-screen it's always the wrong values.
Added/changed code:
Public Sub DrawText(ByVal spritebatch As SpriteBatch, ByVal X As Integer, ByVal Y As Integer, ByVal Text As String)
Dim DX As Integer = X
Dim DY As Integer = Y
For Each C As Char In Text
Dim FC As New FontChar
If _CharacterMap.TryGetValue(C, FC) Then
Dim sourceRectangle = New Rectangle(FC.X, FC.Y, FC.Width, FC.Height)
Dim position = New Vector2(DX + FC.XOffset, DY + FC.YOffset)
spritebatch.Draw(_Texture, position, sourceRectangle, Color.White)
DX += FC.XAdvance
End If
Next
_TextWidth = DX - X
End Sub
Public Function GetTextLength() As Integer
Return _TextWidth
End Function
Screenshot:
Uncentered text, which could be centered if the right values were used for each button
MonoGame.Extended has an implementation of the BMFont renderer with some improvements from that old tutorial, including a SpriteBatch.DrawString
extension.
I've also got a tutorial on my blog about how to set it up. However, it doesn't deal with centering the text so I'll go over that now.
If you choose to use MonoGame.Extended, you should be able to get the centering effect as follows.
First, load your bitmap font as you normally would a SpriteFont
. Note, that for this to work you'll need to setup MonoGame.Extended with the MonoGame Pipeline tool.
_bitmapFont = Content.Load(Of BitmapFont)("my-font")
Next, in your Draw
method you can use GetStringRectangle
to measure the size of the text, then calculate the the correct position. Something like this (sorry if my VB.net is a little rusty):
Dim text = "Start game"
Dim textRectangle = _bitmapFont.GetStringRectangle(text, Vector2.Zero)
Dim textOffset = buttonWidth / 2F - textRectangle.Width / 2F
_spriteBatch.DrawString(_bitmapFont, text, buttonPosition + textOffset, Color.White)
Of course, you don't have to use MonoGame.Extended to do this if you don't want too. I think your code just has a bug, because it looks like it's intended to do what MonoGame.Extended does anyway.
As far as I can tell, your code is calculating the width of the text in the DrawText
method and returning it in the GetTextLength
method. The problem with this approach is that if you call GetTextLength
before DrawText
you're going to get the wrong value.
I assume you're doing something like this:
Dim y = buttonPos.Y
Dim x = buttonPos.X - buttonWidth / 2F - GetTextLength() / 2F
DrawText(_spriteBatch, x, y, text)
Unfortunately, this will not work because GetTextLength
won't return the correct value until after DrawText
runs.
The fix of course, is to actually calculate the text length properly rather than storing it in a member variable during the draw operation.
Public Function GetTextLength(ByVal Text As String) As String
Dim TextWidth As Integer
For Each C As Char In Text
Dim FC As New FontChar
If _CharacterMap.TryGetValue(C, FC) Then
TextWidth += FC.XAdvance
End If
Next
GetTextLength = TextWidth
End Sub