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

unity3D 自定义显示中文

前言:之前有朋友发信来问如何在Neoaxis中显示中文,当时答应写篇教程放上来。后来忙于I'm Lulu King!的制作,就给搁下了。等I'm Lulu King!提交后,却又累得连打开Neoaxis编辑器的劲都没有了。这一拖就拖到了现在。想来这位朋友应该早已解决Neoaxis的中文显示问题了吧,再写教程恐意义不大。Unity的中文显示机制和Neoaxis颇多类似,今天写这篇文章也算是向那位朋友聊表歉意了。 
还要说明的是,笔者才刚开始学习Unity,讲解中有错误或不准确之处还望指正,在此先行谢过。 
1)流程说明Unity的Asset自动导入机制使得在Unity中显示中文非常简单。你所要做的就是将中文字体放到Unity的Asset目录下,Unity会自动将字体中的所有文字转换成一张字体贴图,并生成一个Unity字体。之后你可以就通过GUI Skin\GUI Style引用这个字体来显示中文。 
要在Neoaxis中显示中文的话,生成字体贴图(或称Bitmap Font)的过程不是自动的,你需要先用Bitmap font generator来生成字体贴图及字体定义,然后通过Neoaxis自带的字体转换工具将字体定义转换成Neoaxis的字体定义。对比这两个引擎的字体导入流程,不难发现两者的设计思路差异。Unity的方式简单高效但可控性差,Neoaxis的方式略显繁琐,但你可以精确控制每一个步骤。

2)准备工作让我们先打开任意一个Unity项目,这里我们用的是Unity官方教程中的3D平台游戏项目。 
Unity的GUI采用的是Immediate Mode GUI(IM GUI),对于更习惯Windows GUI编程的朋友来说如果第一次接触可能有点不习惯。简单说来在Unity中创建GUI不需要进行通常的Init(初始化)、CleanUp (清理)步骤,也不需要进行事件的发送、订阅、处理,相反你只需在每帧的更新周期里同时绘制GUI及处理相应事件就可以了。如果想更多了解IM GUI的话,不妨看看mollyrocket.com的这段视频。mollyrocket的论坛里也有不少IM GUI的相关讨论。

在菜单中,选择 GameObject->Create Empty, 创建一个空的GameObject, 改个合适的名字,如"MyGUIObject"。MyGUIObject将充当GUI的容器,具体界面的创建及位置都将通过脚本来进行。所以我们可以不关心这个GameObject在场景中的位置。这时层级视图(Hierarchy)如下:

3)创建 GUI Skin 或 GUI StyleUnity中的界面风格是通过GUI Style及GUI Skin来进行控制。GUI Skin由一组GUI Style组成。GUI Skin和GUI Style的关系类似于CSS中CSS文件和CSS Style之间的关系。本教程的重点不在于Unity GUI的讲解,相关概念大家可以多参看Unity Manual。 
在项目视图(Project)中选择Create->GUI Skin创建一个GUI Skin,改名为"ChineseFontSkin"。这时项目视图如下:

在属性视图(Inspector)中对ChineseFontSkin简单设置如下:

这时我们还没有中文字体,字体一项就先用项目中带的Fluoride字体,然后将Button中Normal的Text Color改成黄色。Button是这个GUI Skin中关于按钮的默认Style。 

然后,我们将Label中Normal的Text Color改成绿色。本教程只用到Button和Label。 
4)通过脚本创建GUI在Unity中你可以通过GameObject菜单创建GUI Text和GUI Texture这两个基本的GUI对象。但大部分GUI都需要通过脚本创建。我们将用脚本创建一个Label和一个Button。 
在项目视图(Project)中选择Scripts下的GUI目录,在本视图的菜单中旋转Create->C Sharp Script, 创建一个C Sharp脚本,改名为“MyGUI”。 
双击MyGUI脚本可以在Unity自带的UniSciTE编辑器中打开脚本进行编辑。但由于UniSciTE无法正确显示中文字符,使用外部IDE来编辑带中文的脚本是个好主意。微软的Visual C# Express当然是免费编辑器中的首选, 但对于我们这个简单的脚本来说,Notepad就足够了。 
在Unity项目视图中右键点击"MyGUI",在弹出菜单中选择“Show in Explorer”,可以看到我们的脚本文件。 

用Notepad打开MyGUI.cs,输入以下脚本:

这个脚本做的事很简单。先定义一个可设置的GUISkin对象mySkin。在OnGUI方法中将GUI的Skin设为mySkin, 然后创建一个Label和一个Button。Label中显示的中文拷贝自我们站点的About页(上面截图中文字未显示完整)。保存脚本,用默认的Ascii编码保存即可。 
回到Unity,将MyGUI脚本拖放到MyGUIObject上。选择MyGUIObject,在Inspector中将My Skin 设为"ChineseFontSkin"。

运行游戏,可以看到英文文字能显示,但中文都丢了。这是因为我们还没有导入中文字体的缘故。 

5) 导入中文字体在Windows的Font目录下,选择你喜欢的中文字体(这里我们选择微软雅黑),拷贝至Unity项目下的Assets\GUI目录下。切换至Unity,发现Unity呈冻结状,此时Unity正在进行字体贴图及字体定义的自动生成工作。根据机器性能及字体大小,导入过程可能较长。(我的机器上需要10多分钟。) 
等Unity完成工作后,可以看到Project视图下的GUI目录中多了个msyh的字体。(或其他你选择的字体的名称) 
在Project视图中选择ChineseFontSkin,在Inspector视图中,将Font改为刚导入的字体msyh。再运行游戏。

中文都可以显示了。你好,Unity! 
6)Unity干了什么及没干什么?在Unity中显示中文是不是很简单呢? 
再让我们看看Unity在背后干了些什么。在Project视图中选择msyh字体并展开,可以看到Unity为每个字体生成了一个字体贴图(font texture)及一个字体材质(font material)。选择font texutre, 在Inspector视图可以看到该贴图的预览:

一张16M的4096x4096贴图! 
Unity自动替你将微软雅黑中所有可用文字都导成了一张巨大的位图,而不管你是否真的需要这么多文字。好处在于,现在你可以在Unity里显示所有微软雅黑字体所支持的文字了。但是,为每个字体分配一张16M贴图的做法太过奢侈了,对配置较低的机器或是iPhone来说更是不可接受。可是在Unity真正支持TTF字体渲染之前,我们似乎也只好接受这种傻瓜式生成字体贴图的方式。 
但我们对此真的无能为力了吗?当然不!既然我们无法控制Unity生成字体贴图的方式及过程(虽然通过Editor API的TrueTypeFontImporter类可以进行有限的控制),至少我们可以对字体本身做些改造,让它只包含我们所需要的文字。就我们这个简单的项目而言,我们希望看到的字体贴图更应该是下面这样的:


64K vs 16M。除非你要开发RPG或是需要用户输入任意中文,改造字体的成效将非常可观的。 
在下一篇教学中我们将介绍如何利用FontForge来完成中文字体的瘦身工作。 

相关文章:

  • Eclipse中将class。Java打包成Jar
  • Java Web实习笔记
  • JAVA中indexOf函数用法和subString()方法
  • MyEclipse+Tomcat + Servlet开发
  • Servlet学习
  • JAVA中Iterator的具体作用?
  • 实习日志(3)
  • FileItem类
  • JSP中EL表达式语言不能使用的解决方法
  • myeclipse中文乱码,JSP页面乱码
  • Tomcat中文乱码问题的原理和解决方法
  • java的web.xml中出现ERROR:Editor model does not support child element taglib of web
  • quote symbol expected异常
  • JAVA操作properties文件
  • JSP九个隐式对象
  • JS 中的深拷贝与浅拷贝
  • __proto__ 和 prototype的关系
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 2017 年终总结 —— 在路上
  • Git同步原始仓库到Fork仓库中
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Mysql数据库的条件查询语句
  • python大佬养成计划----difflib模块
  • Web设计流程优化:网页效果图设计新思路
  • 安装python包到指定虚拟环境
  • 不上全站https的网站你们就等着被恶心死吧
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 从输入URL到页面加载发生了什么
  • - 概述 - 《设计模式(极简c++版)》
  • 给新手的新浪微博 SDK 集成教程【一】
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 聚簇索引和非聚簇索引
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 为什么要用IPython/Jupyter?
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​flutter 代码混淆
  • !$boo在php中什么意思,php前戏
  • # include “ “ 和 # include < >两者的区别
  • #pragam once 和 #ifndef 预编译头
  • #微信小程序:微信小程序常见的配置传旨
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (4)logging(日志模块)
  • (6)STL算法之转换
  • (a /b)*c的值
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (vue)页面文件上传获取:action地址
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)四层和七层负载均衡的区别
  • (转)用.Net的File控件上传文件的解决方案
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .md即markdown文件的基本常用编写语法