当前位置: 首页 > article >正文

Libgdx游戏开发系列教程(4)——显示中文文字

目录

2种方法优缺点

BitmapFont

FreeTypeFont 

方法1 使用BitmapFont 

1.下载hiero工具

 2.生成fnt文件

3.代码使用 

测试效果 

方法2 使用FreeType 

1.依赖引入

2.代码使用 

测试效果

使用疑问点


这里主要介绍关于在Libgdx显示文字的2种方法

本文代码示例采用kotlin代码进行讲解,且需要有libgdx入门基础

2种方法优缺点

BitmapFont

优势:

  1. 易于操作和使用,简单快速实现文本渲染。
  2. 资源消耗相对较低,速度较快。
  3. 支持利用工具生成位图字体,可以实现自定义字体样式。

缺点:

  1. 缩放时可能导致文字变得模糊。
  2. 不支持平滑缩放,容易出现锯齿效果。
  3. 需要手动创建位图字体文件,可能需要额外的工作量。
FreeTypeFont 

优势:

  1. 支持平滑缩放和旋转,渲染效果更加平滑、清晰。
  2. 支持各种字体格式,更加灵活。
  3. 可以在运行时动态加载字体文件。

缺点:

  1. 资源消耗相对较高,速度较BitmapFont略慢。
  2. 对于大型字体或文本,内存占用可能较高。
  3. 需要额外的库(FreeType)支持,增加了依赖

方法1 使用BitmapFont 

1.下载hiero工具

在Hiero - libGDX页面中下载hiero工具,如下图

下载下来的是一个jar文件,通过java -jar命令打开即可(我自己用的是JDK8,看软件页面应该是使用的swing相关组件,高版本java环境应该也是能够打开)

软件界面下图所示

 2.生成fnt文件

我们需要使用hiero工具生成一个fnt文件(从翻译上来说是一个字体的位图文件,即每个字符都是一个位图)

左侧我们可以选择系统ttf字体或者从文件中选择一个ttf文件来生成(以及进行一些字体大小,加粗或斜体设置)

可以看到渲染方式有三种,具体官方解释如下:

  • FreeType: 通常质量最高。它充分利用了提示,这意味着小字体可以很好地呈现。该gamma设置控制抗锯齿程度。该mono设置禁用所有字体平滑。不支持其他效果,但可以使用填充和通过 Photoshop 或其他工具应用的效果来渲染字形。Hiero 使用 gdx-freetype,因此生成的位图字体将与 gdx-freetype 即时渲染的字体完全匹配。
  • Java: 此字体渲染为字形提供了矢量轮廓,允许应用各种效果,例如阴影、轮廓等。小尺寸的输出通常很模糊,但大尺寸的输出质量很好。
  • Natvie: 操作系统原生渲染最为简单。它不提供紧密贴合的边界,因此字形会占用更多的图集空间。

在右边的输入框中,输入相关文字,点击file菜单栏即可生成fnt文件,如下图所示

有大佬提及使用过程中会有失真的过程,可以看着调整page width和page height属性,调大些 

3.代码使用 
package com.arthurlumertz.taplixic

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.ApplicationListener
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch

class BitmapFontTest : ApplicationAdapter() {
    lateinit var batch: SpriteBatch
    lateinit var font: BitmapFont

    override fun create() {
		//读取fnt和png文件生成BitmapFont对象
        font = BitmapFont(Gdx.files.internal("testfont/myfont.fnt"), Gdx.files.internal("testfont/myfont.png"), false)
        font!!.setColor(0.5f, 0.4f, 0.6f, 1f) // 设置颜色

        batch = SpriteBatch()
    }
    
    override fun render() {
        Gdx.gl.glClearColor(1f, 1f, 1f, 1f)
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)

		//绘制操作
        batch!!.begin()
		//这里可以采用\n实现换行效果,
        font!!.draw(batch, "我的\n下一行", 200f, 160f)
        batch!!.end()
    }

    override fun dispose() {
		//资源释放
        batch!!.dispose()
        font!!.dispose()
    }
}

需要注意:

  1. 绘制文字需要考虑y坐标
  2. 文字必须是你之前在工具里输入里的文字,如果不是的话,显示就会出现口这种特殊字符
  3. 使用\n可以实现换行效果

比如你设置要在(0,0)处绘制文字,文字底部就会被遮挡了,如下图效果

测试效果 

启动游戏的代码,不用多解释了

package com.arthurlumertz.taplixic;

import com.badlogic.gdx.backends.lwjgl3.*;

public class DesktopLauncher {

	public static void main (String[] arg) {
		Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
		config.setWindowedMode(960, 540);
		config.setForegroundFPS(60);
		new Lwjgl3Application(new BitmapFontTest(), config);
	}

}

上图显示口这种字符就是我的生成fnt文件里没有定义的文字 

方法2 使用FreeType 

此方法最终也是使用上述的BitmapFont对象来进行绘制

只是使用FreeTypeFontGenerator类将ttf生成了BitmapFont对象,之后的使用方法与上述绘制方法一致

我这里是去系统里随便找了个ttf字体文件来使用

1.依赖引入

在主工程中加入依赖:

api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"

对应在desktop平台的build.gradle加入依赖

api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"

如果是Android平台,则加入下面依赖:

api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"

如果你之前创建libgdx项目的时候勾选了FreeType,就会自动生成对应的依赖了

2.代码使用 
package com.arthurlumertz.taplixic

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.ApplicationListener
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter

class FreetypeFontTest : ApplicationAdapter() {
    lateinit var batch: SpriteBatch

    // 系统字体
    lateinit var systemFont: BitmapFont

    lateinit var generator: FreeTypeFontGenerator

    override fun create() {
        batch = SpriteBatch()
		//自己找的一个ttf文件
        generator = FreeTypeFontGenerator(Gdx.files.internal("testfont/cnfont.ttf"))

        // 字体参数设置
        val parameter = FreeTypeFontParameter()
        parameter.size = 18

		//需要使用的文字,里面不能有相同
        //parameter.characters = FreeTypeFontGenerator.DEFAULT_CHARS + "你好我的" // 默认字体需要提前设置好字符
		
		//chinese.txt文件内容里是我上面提到的三千个汉字文本
        parameter.characters = FreeTypeFontGenerator.DEFAULT_CHARS + Gdx.files.internal("testfont/chinese.txt").readString()

		//生成BitmapFont对象
        systemFont = generator!!.generateFont(parameter)
    }


    override fun render() {
        batch!!.begin()

        systemFont!!.draw(batch, "你好的我的,这是一个数据哈哈\n下一行数据", 0f, 300f)

        batch!!.end()
    }

    override fun dispose() {
        batch!!.dispose()
        systemFont!!.dispose()
        generator!!.dispose()
    }
}

注意点:

parameter.characters设置的字符不能有重复,因为代码逻辑是要根据字符作为key找对应的index(个人的简单理解)

比如说你要展示文本: '今天天气真好',你的parameter.characters应该设置为今天气真好

上面例子我是直接用了三千的文字进行生成,但这样做法会消耗很大内存,官方不太推荐

看官方说用到什么文字就创建什么文字,但这样来不是会麻烦?还得处理下将重复字给过滤掉?这里我暂且持保留意见吧

补充FreeTypeFontParameter可设置属性:

/** The size in pixels */
public int size = 16;
/** Foreground color (required for non-black borders) */
public Color color = Color.WHITE;
/** Border width in pixels, 0 to disable */
public float borderWidth = 0;
/** Border color; only used if borderWidth > 0 */
public Color borderColor = Color.BLACK;
/** true for straight (mitered), false for rounded borders */
public boolean borderStraight = false;
/** Offset of text shadow on X axis in pixels, 0 to disable */
public int shadowOffsetX = 0;
/** Offset of text shadow on Y axis in pixels, 0 to disable */
public int shadowOffsetY = 0;
/** Shadow color; only used if shadowOffset > 0 */
public Color shadowColor = new Color(0, 0, 0, 0.75f);
/** The characters the font should contain */
public String characters = DEFAULT_CHARS;
/** Whether the font should include kerning */
public boolean kerning = true;
/** The optional PixmapPacker to use */
public PixmapPacker packer = null;
/** Whether to flip the font vertically */
public boolean flip = false;
/** Whether or not to generate mip maps for the resulting texture */
public boolean genMipMaps = false;
/** Minification filter */
public TextureFilter minFilter = TextureFilter.Nearest;
/** Magnification filter */
public TextureFilter magFilter = TextureFilter.Nearest;

测试效果

启动游戏的代码,应该不用多解释了

package com.arthurlumertz.taplixic;

import com.badlogic.gdx.backends.lwjgl3.*;

public class DesktopLauncher {

	public static void main (String[] arg) {
		Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
		config.setWindowedMode(960, 540);
		config.setForegroundFPS(60);
		new Lwjgl3Application(new FreetypeFontTest(), config);
	}
}

使用疑问点

下面是一下疑问点的记录,还没有具体研究得到答案,先记录着吧,或者有路过的大佬可以在评论区解答下?

  1. FreeType每次都得生成对应字符,不能直接使用单例,一次性生成要使用的字符,之后直接使用吗?
  2. 关于语言国际化的要求应该如何实现?感觉有些偏题,应该是可以使用类似的一个资源文件来自行管理,由用户选择对应的语言就加载文本,参考杀戮尖塔的语言更改,应该是需要重启游戏才能解决,不能动态实现
  3. BitmapFont会有失真的缺点,应该如何解决优化,有无优化方法?

http://www.kler.cn/a/571976.html

相关文章:

  • Kubernetes教程(三)Docker容器命令
  • 股市现期驱动因子
  • go:windows环境下安装Go语言
  • AWS中使用CloudFront分发API Gateway
  • 计算机毕业设计SpringBoot+Vue.js工作流程管理系统(源码+文档+PPT+讲解)
  • 迷你世界脚本状态接口:Buff
  • 360图片爬虫|批量爬取图片
  • Vue05
  • QT-自定义参数设计框架软件
  • 爬虫(持续更新ing)
  • wordpress子分类调用父分类名称和链接的3种方法
  • Android 系统开发的指导文档
  • 奇安信天擎面试题
  • 未来经济范式争夺战:AR眼镜为何成为下一代交互终端的制高点?
  • 【TCP/IP协议栈】2. 网络接口层协议(以太网、令牌环、PPP 等)
  • 【STM32】TIM输入捕获-学习笔记
  • 2025年能源工作指导意见
  • 【Unity】鼠标在某区域悬停触发文本框,移开关闭文本框
  • 蔡司智锐系列眼镜:智能动态护眼,畅享数字化生活
  • doris: Hive