BitmapFont 的自定义角色 (libgdx)
Custom actor for BitmapFont (libgdx)
我花了几个令人沮丧的时间来尝试实现(我认为会是)一个简单的 FontActor
class.
想法是使用提供的 BitmapFont
在特定位置绘制文本。这么多,我已经设法完成了。但是,我正在努力根据呈现的文本计算演员的 width/height。
(使用 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()
}
}
在我的 parent Screen
class 实现中,我会在每次 window 调整大小时重新缩放字体,这样它们就不会变成 "smooshed" 或拉伸:
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) }
}
}
在您调整 window 大小之前,这很有效并且看起来很棒。
调整大小后,字体看起来很好,并自动调整 window 的相对大小,但是 FontActor
的大小不正确,因为我对 setSize
的调用是错误的。
初始window:
水平放大 window 后:
例如,如果我然后水平缩放 window(这对世界大小没有影响,因为我使用的是 FitViewport
),字体看起来正确,正如预期.然而,从 draw()
返回的 layout.width
值发生了变化,即使文本大小没有改变 on-screen。经过调查,我意识到这是由于我使用了 setScale
,但简单地将宽度除以 x-scaling 因子并不能纠正错误。再一次,如果我删除我的 setScale
电话,数字是有意义的,但字体现在被压扁了!
我尝试的另一种策略是将 width/height 转换为屏幕坐标,然后使用相关的 project/unproject 方法获取世界坐标中的宽度和高度。这与图片中显示的问题相同。
我该如何解决我的数学问题?
或者,是否有 smarter/easier 方法来实现所有这些?(不,我不想要 Label
,我只想要一个文本演员。)
一个问题是我的缩放代码。
解决方法是更改相机更新,如下所示:
context.inject<OrthographicCamera>().setToOrtho(false, stage.viewport.screenWidth.toFloat(), stage.viewport.screenHeight.toFloat())
这导致我的文本相机与世界视口相机相匹配。我正在使用整个屏幕进行计算,因此会拉伸。
我的 scaleX
/Y
计算错误也是出于同样的原因。在更正了这两个错误计算之后,我得到了一个很好的缩放 FontActor
,在世界坐标中具有正确的边界。
我花了几个令人沮丧的时间来尝试实现(我认为会是)一个简单的 FontActor
class.
想法是使用提供的 BitmapFont
在特定位置绘制文本。这么多,我已经设法完成了。但是,我正在努力根据呈现的文本计算演员的 width/height。
(使用 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()
}
}
在我的 parent Screen
class 实现中,我会在每次 window 调整大小时重新缩放字体,这样它们就不会变成 "smooshed" 或拉伸:
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) }
}
}
在您调整 window 大小之前,这很有效并且看起来很棒。
调整大小后,字体看起来很好,并自动调整 window 的相对大小,但是 FontActor
的大小不正确,因为我对 setSize
的调用是错误的。
初始window:
水平放大 window 后:
例如,如果我然后水平缩放 window(这对世界大小没有影响,因为我使用的是 FitViewport
),字体看起来正确,正如预期.然而,从 draw()
返回的 layout.width
值发生了变化,即使文本大小没有改变 on-screen。经过调查,我意识到这是由于我使用了 setScale
,但简单地将宽度除以 x-scaling 因子并不能纠正错误。再一次,如果我删除我的 setScale
电话,数字是有意义的,但字体现在被压扁了!
我尝试的另一种策略是将 width/height 转换为屏幕坐标,然后使用相关的 project/unproject 方法获取世界坐标中的宽度和高度。这与图片中显示的问题相同。
我该如何解决我的数学问题?
或者,是否有 smarter/easier 方法来实现所有这些?(不,我不想要 Label
,我只想要一个文本演员。)
一个问题是我的缩放代码。 解决方法是更改相机更新,如下所示:
context.inject<OrthographicCamera>().setToOrtho(false, stage.viewport.screenWidth.toFloat(), stage.viewport.screenHeight.toFloat())
这导致我的文本相机与世界视口相机相匹配。我正在使用整个屏幕进行计算,因此会拉伸。
我的 scaleX
/Y
计算错误也是出于同样的原因。在更正了这两个错误计算之后,我得到了一个很好的缩放 FontActor
,在世界坐标中具有正确的边界。