我花了几个令人沮丧的时间来尝试实现一个简单的FontActor类。

想法是使用提供的BitmapFont仅在特定位置绘制文本。这么多,我就成功完成了。但是,我正在努力根据渲染的文本来计算演员的宽度/高度。

(使用FitViewport进行测试)

open class FontActor<T : BitmapFont>(val font: T, var text: CharSequence = "") : GameActor() {
    val layout = Pools.obtain(GlyphLayout::class.java)!!

    companion object {
        val identity4 = Matrix4().idt()
        val distanceFieldShader: ShaderProgram = DistanceFieldFont.createDistanceFieldShader()
    }

    override fun draw(batch: Batch?, parentAlpha: Float) {
        if (batch == null) return
        batch.end()

        // grab ui camera and backup current projection
        val uiCamera = Game.context.inject<OrthographicCamera>()
        val prevTransform = batch.transformMatrix
        val prevProjection = batch.projectionMatrix
        batch.transformMatrix = identity4
        batch.projectionMatrix = uiCamera.combined
        if (font is DistanceFieldFont) batch.shader = distanceFieldShader

        // the actor has pos = x,y in local coords, but we need UI coords
        // start by getting group -> stage coords (world)
        val coords = Vector3(localToStageCoordinates(Vector2(0f, 0f)), 0f)

        // world coordinate destination -> screen coords
        stage.viewport.project(coords)

        // screen coords -> font camera world coords
        uiCamera.unproject(coords,
                stage.viewport.screenX.toFloat(),
                stage.viewport.screenY.toFloat(),
                stage.viewport.screenWidth.toFloat(),
                stage.viewport.screenHeight.toFloat())

        // adjust position by cap height so that bottom left of text aligns with x, y
        coords.y = uiCamera.viewportHeight - coords.y + font.capHeight

        /// TODO: use BitmapFontCache to prevent this call on every frame and allow for offline bounds calculation
        batch.begin()
        layout.setText(font, text)
        font.draw(batch, layout, coords.x, coords.y)
        batch.end()

        // viewport screen coordinates -> world coordinates
        setSize((layout.width / stage.viewport.screenWidth) * stage.width,
                (layout.height / stage.viewport.screenHeight) * stage.height)

        // restore camera
        if (font is DistanceFieldFont) batch.shader = null
        batch.projectionMatrix = prevProjection
        batch.transformMatrix = prevTransform
        batch.begin()
    }
}


在父级Screen类实现中,我在每次调整窗口大小时都调整字体大小,以免字体“变滑”或拉伸:

override fun resize(width: Int, height: Int) {
    stage.viewport.update(width, height)
    context.inject<OrthographicCamera>().setToOrtho(false, width.toFloat(), height.toFloat())

    // rescale fonts
    scaleX = width.toFloat() / Config.screenWidth
    scaleY = height.toFloat() / Config.screenHeight
    val scale = minOf(scaleX, scaleY)
    gdxArrayOf<BitmapFont>().apply {
        Game.assets.getAll(BitmapFont::class.java, this)
        forEach { it.data.setScale(scale) }
    }
    gdxArrayOf<DistanceFieldFont>().apply {
        Game.assets.getAll(DistanceFieldFont::class.java, this)
        forEach { it.data.setScale(scale) }
    }
}


在您调整窗口大小之前,此方法有效且看起来不错。
调整大小后,字体看起来不错,并会根据窗口的相对大小自动调整,但是FontActor的大小错误,因为我对setSize的调用是错误的。

初始窗口:

java - BitmapFont(libgdx)的自定义角色-LMLPHP

将窗口水平增大后:

java - BitmapFont(libgdx)的自定义角色-LMLPHP

例如,如果我然后水平缩放窗口(这对世界尺寸没有影响,因为我使用的是FitViewport),则字体看起来像预期的那样正确。但是,即使文本大小没有在屏幕上更改,从layout.width返回的draw()值也会更改。经过调查,我意识到这是由于使用了setScale,但是仅将宽度除以x缩放因子并不能纠正该错误。再说一次,如果我删除了setScale调用,数字就很有意义了,但是现在字体已经压缩了!

我尝试的另一种策略是将宽度/高度转换为屏幕坐标,然后使用相关的project / unproject方法获取世界坐标中的宽度和高度。这也遇到了图像中显示的相同问题。

如何修正数学?

或者,是否有更聪明/更简便的方法来实现所有这些功能? (不,我不需要Label,我只想要一个文本演员。)

最佳答案

一个问题是我的缩放代码。
解决方法是按以下方式更改相机更新:

context.inject<OrthographicCamera>().setToOrtho(false, stage.viewport.screenWidth.toFloat(), stage.viewport.screenHeight.toFloat())


这导致我的文字相机与世界视口相机匹配。我将整个屏幕用于计算,因此进行了拉伸。

由于相同的原因,我的scaleX / Y计算错误。纠正了所有这些错误计算之后,我在世界坐标中使用正确的边界很好地缩放了FontActor

10-08 17:39