PixelText.cs
namespace Sandbox;
/// <summary>
/// Utility for drawing bitmap text using the "text" sprite font data.
/// Each glyph is 3×5 pixels; characters are spaced 4px apart (3 + 1 gap).
/// Supports lowercase a-z and digits 0-9. Unknown characters are skipped.
///
/// Usage:
/// PixelText.Draw( 10, 10, "hello", new Color32( 255, 255, 255, 255 ) );
/// </summary>
public static class PixelText
{
/// <summary>Glyph width in pixels.</summary>
public const int GlyphWidth = 3;
/// <summary>Glyph height in pixels.</summary>
public const int GlyphHeight = 5;
/// <summary>Horizontal advance per character (glyph + 1px gap).</summary>
public const int Advance = 4;
/// <summary>Vertical line spacing (glyph + 1px gap).</summary>
public const int LineHeight = 6;
/// <summary>
/// Draw a string into the <see cref="PixelScreen"/> at the given position.
/// Text is rendered left-to-right; newlines (\n) move to the next row.
/// The <paramref name="color"/> replaces the font's default black pixels.
/// </summary>
public static void Draw( int x, int y, string text, Color32 color )
{
PixelScreen screen = PixelScreen.Instance;
if ( screen is null )
return;
// Ensure text sprites are loaded.
if ( !SpriteManager.IsLoaded )
SpriteManager.LoadAll();
int cursorX = x;
int cursorY = y;
Color32 black = new Color32( 0, 0, 0, 255 );
foreach ( char c in text )
{
if ( c == '\n' )
{
cursorX = x;
cursorY -= LineHeight; // Y goes up in our coordinate system.
continue;
}
if ( c == ' ' )
{
cursorX += Advance;
continue;
}
// The text sprite uses the character itself as the animation name.
string glyphName = char.ToLowerInvariant( c ).ToString();
AnimationData anim = SpriteManager.GetAnimation( "text", glyphName );
if ( anim is null || anim.Frames.Count == 0 )
{
cursorX += Advance;
continue;
}
FrameData frame = anim.Frames[0];
foreach ( PixelData pixel in frame.Pixels )
{
int px = cursorX + pixel.Position.X;
int py = cursorY + pixel.Position.Y;
// Replace the font's black with the requested colour.
Color32 drawColor = (pixel.Color.r == black.r && pixel.Color.g == black.g && pixel.Color.b == black.b)
? color
: pixel.Color;
if ( drawColor.a == 255 )
screen.SetPixel( px, py, drawColor );
else if ( drawColor.a > 0 )
screen.AddPixel( px, py, drawColor );
}
cursorX += Advance;
}
}
/// <summary>
/// Measure the pixel width a string would occupy when drawn.
/// </summary>
public static int MeasureWidth( string text )
{
int maxWidth = 0;
int lineWidth = 0;
foreach ( char c in text )
{
if ( c == '\n' )
{
maxWidth = Math.Max( maxWidth, lineWidth );
lineWidth = 0;
continue;
}
lineWidth += Advance;
}
maxWidth = Math.Max( maxWidth, lineWidth );
// Remove the trailing 1px gap from the last character.
return maxWidth > 0 ? maxWidth - 1 : 0;
}
/// <summary>
/// Draw text centered horizontally within the screen.
/// </summary>
public static void DrawCentered( int y, string text, Color32 color )
{
PixelScreen screen = PixelScreen.Instance;
if ( screen is null )
return;
int width = MeasureWidth( text );
int x = (screen.PixelWidth - width) / 2;
Draw( x, y, text, color );
}
}