如何在Golang Ebitengine v2中显示大尺寸棋盘棋子文本?
问题描述
我做了一个棋盘,需要在上面显示K、Q、P这类棋子文本,但目前只能显示小字体。请问怎么在屏幕上显示更大的文本?比如字号32。
我试过用basicfont包创建字体,但没法放大。理想情况是用Ebitengine v2在屏幕指定位置显示任意尺寸、颜色文本的简便方法。
附带代码示例:
package main import ( "fmt" "image/color" "log" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/text" "github.com/hajimehoshi/ebiten/v2/vector" "golang.org/x/image/font/basicfont" ) // Game represents the game state type Game struct { } func (g *Game) Update() error { return nil } func (g *Game) Draw(screen *ebiten.Image) { vector.DrawFilledRect(screen, float32(0), float32(0), float32(100), float32(100), color.Black, true) vector.DrawFilledRect(screen, float32(100), float32(0), float32(100), float32(100), color.White, true) // print text, default ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%v", "K"), 50, 50) //with color, but font is still small exampleImage := ebiten.NewImage(50, 50) exampleImage.Fill(color.RGBA{0x00, 0x00, 0xff, 0xff}) op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(125), float64(25)) screen.DrawImage(exampleImage, op) var myFont = &basicfont.Face{ Advance: 7, Width: 32, Height: 32, Ascent: 11, Descent: 2, Mask: basicfont.Face7x13.Mask, Ranges: []basicfont.Range{ {'\u0020', '\u007f', 0}, {'\ufffd', '\ufffe', 95}, }, } text.Draw(screen, fmt.Sprint("Q"), myFont, 150, 50, color.RGBA{0xff, 0x00, 0x00, 0xff}) } func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { return 640, 640 } func main() { ebiten.SetWindowSize(640, 640) if err := ebiten.RunGame(&Game{}); err != nil { log.Fatal(err) } }
解决方案
basicfont是点阵字体,本身尺寸固定,修改Face的Width/Height参数只会改变布局空间,不会真正放大字体。要实现任意尺寸的文本显示,推荐使用Ebitengine的text/v2包,它支持矢量字体缩放,具体步骤如下:
1. 替换并新增依赖包
替换原有的text包导入为text/v2,同时添加字体解析相关的依赖:
import ( // ...原有其他导入 "github.com/hajimehoshi/ebiten/v2/text/v2" "golang.org/x/image/font" "golang.org/x/image/font/opentype" )
2. 加载矢量字体
可以加载系统自带字体,也可以嵌入自定义字体文件。以下示例以加载系统字体为例:
var largeFont font.Face func init() { // 替换为对应系统的字体路径: // Windows: "C:/Windows/Fonts/arial.ttf" // macOS: "/Library/Fonts/Arial.ttf" // Linux: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" fontPath := "/Library/Fonts/Arial.ttf" fontBytes, err := os.ReadFile(fontPath) if err != nil { log.Fatalf("加载字体失败: %v", err) } tt, err := opentype.Parse(fontBytes) if err != nil { log.Fatalf("解析字体失败: %v", err) } // 创建32号字体实例 const fontSize = 32 largeFont, err = opentype.NewFace(tt, &opentype.FaceOptions{ Size: fontSize, DPI: 72, Hinting: font.HintingFull, }) if err != nil { log.Fatalf("创建字体Face失败: %v", err) } }
3. 绘制大尺寸文本
在Draw方法中使用text/v2的Draw函数,支持指定位置、颜色和字体:
func (g *Game) Draw(screen *ebiten.Image) { // ...原有棋盘绘制代码 // 绘制32号黑色K(注意文本基线位置,需加上字体 ascent 偏移) kOpts := &text.DrawOptions{} kOpts.GeoM.Translate(50, 50+float64(largeFont.Metrics().Ascent.Floor())) text.Draw(screen, "K", largeFont, kOpts) // 绘制32号红色Q qOpts := &text.DrawOptions{} qOpts.GeoM.Translate(150, 50+float64(largeFont.Metrics().Ascent.Floor())) qOpts.ColorScale.ScaleWithColor(color.RGBA{0xff, 0x00, 0x00, 0xff}) text.Draw(screen, "Q", largeFont, qOpts) }
替代方案:缩放点阵文本图像
如果不想使用矢量字体,也可以先将文本绘制到临时图像,再通过缩放实现大字体效果:
func drawScaledText(screen *ebiten.Image, str string, face font.Face, x, y float64, scale float64, col color.Color) { bounds, _ := text.BoundString(face, str) img := ebiten.NewImage(bounds.Dx(), bounds.Dy()) img.Fill(color.Transparent) text.Draw(img, str, face, -bounds.Min.X, -bounds.Min.Y, col) op := &ebiten.DrawImageOptions{} op.GeoM.Scale(scale, scale) op.GeoM.Translate(x, y-float64(bounds.Max.Y)*scale) screen.DrawImage(img, op) } // 在Draw方法中调用(放大3倍) drawScaledText(screen, "K", basicfont.Face7x13, 50, 50, 3, color.Black)
完整修改后的代码
package main import ( "image/color" "log" "os" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/text/v2" "github.com/hajimehoshi/ebiten/v2/vector" "golang.org/x/image/font" "golang.org/x/image/font/opentype" ) var largeFont font.Face func init() { // 替换为你的系统字体路径 fontPath := "/Library/Fonts/Arial.ttf" fontBytes, err := os.ReadFile(fontPath) if err != nil { log.Fatalf("加载字体失败: %v", err) } tt, err := opentype.Parse(fontBytes) if err != nil { log.Fatalf("解析字体失败: %v", err) } const fontSize = 32 largeFont, err = opentype.NewFace(tt, &opentype.FaceOptions{ Size: fontSize, DPI: 72, Hinting: font.HintingFull, }) if err != nil { log.Fatalf("创建字体Face失败: %v", err) } } type Game struct{} func (g *Game) Update() error { return nil } func (g *Game) Draw(screen *ebiten.Image) { // 绘制棋盘格子 vector.DrawFilledRect(screen, float32(0), float32(0), float32(100), float32(100), color.Black, true) vector.DrawFilledRect(screen, float32(100), float32(0), float32(100), float32(100), color.White, true) // 绘制32号黑色K kOpts := &text.DrawOptions{} kOpts.GeoM.Translate(50, 50+float64(largeFont.Metrics().Ascent.Floor())) text.Draw(screen, "K", largeFont, kOpts) // 绘制32号红色Q qOpts := &text.DrawOptions{} qOpts.GeoM.Translate(150, 50+float64(largeFont.Metrics().Ascent.Floor())) qOpts.ColorScale.ScaleWithColor(color.RGBA{0xff, 0x00, 0x00, 0xff}) text.Draw(screen, "Q", largeFont, qOpts) } func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { return 640, 640 } func main() { ebiten.SetWindowSize(640, 640) if err := ebiten.RunGame(&Game{}); err != nil { log.Fatal(err) } }
内容的提问来源于stack exchange,提问作者ASH
相关产品推荐
相关产品推荐

