Xna支持中文显示方法归纳
2010-11-04 21:49
483 查看
Xna不同于DirectX,因其内部并未提供类似于D3DFont的机制(据说之所以会这样做,也是考虑到与Xbox360兼容的缘故),使得显示中文变得极为不便。
虽然如此,要实现Xna下的中文显示依然存在多种方法:
1.添加SpriteFont,修该他的CharacterRegion的Start和End,范围就是中文的Unicode范围。
因为通常大家不太好定位自己所需汉字的Unicode范围,而该范围又不允许无限制扩大,因此不可取~
2.GDI+
使用GDI+虽然能够满足中文显示的要求,但众所周知,GDI+本身的效率是个问题,因此,也不建议大家使用这种方法。
相关内容,请参考:http://www.cnblogs.com/XnaZero/archive/2009/03/29/1412148.html ,为XnaZero兄原创~
XNA3.0内带例子 SpriteFontX_1_0_2_1.rar
XNA3.1内带例子 SpriteFontX_1_0_2_1_For_Xna3_1.rar
XNA4.0内带例子 SpriteFontX_1_0_2_2_For_Xna4.rar
XNA支持中文输入示例 http://xna.omgsoft.com.cn/education/XNA_IME.aspx (Xna游戏世界)
作者没有开源,因此不太清楚内部机制,但个人猜想核心部分或许是这样的:
调用方法生成中文纹理,而后使用SpriteBatch绘制即可~
3.字体纹理
相比以上两种方法而言,这种方法算是较为正统的Xna中文显示方法,借用Xna的ContentPipeline,这种方法的效率算是比较不错的。此种方法较为可取。
相关内容,请参考:http://kb.cnblogs.com/a/1459016/,为clayman兄原创~
其实要实现所谓的字体纹理,关键的核心方法有两个:
而追根究底,这两个方法实现的其实就是纹理间内存数据的拷贝而已。
整个方法原理如下:
1.准备好事先生成的“字库”(可以用Gdi+,好像还有一个开源的工具叫做ttf2bmp),其实就是带有通用中文字符的纹理。
2.程序启动时,通过内容管线,事先将其加载到内存,也就是一个Texture2D对象里。这里我们称作原始纹理。
3.需要绘制中文字符时,事先new一个空白的Texture2D。这里我们称作目标纹理。
4.根据字符的位置对应关系,从原始纹理中截取所要绘制的字符数据,赋值给目标纹理。
5.绘制目标纹理即可。
如上方法中,用到的其实也仅仅就是GetData与SetData。
其中需要注意的问题有两点:
1.生成的目标纹理,规格需要与原始纹理相同。
这里的规格,其实也就是指Texture2D构造函数中的【int numberLevels, TextureUsage usage, SurfaceFormat format】三个参数。那么如何来解决这个问题呢?其实很简单,从原始纹理中获取这三个属性,传入目标纹理的构造函数中即可。这样一来,目标纹理与原始纹理规格绝对相同。
不知是否有人要问,原始纹理的规格你如何获得?呵~ 这个你自然不用管,因为有Xna的内容管线替你完成~
2.使用GetData从原始纹理获取数据时,各个参数的确定问题。
我们获取数据,一般要用到此方法的第三个重载方法,即:
public void GetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount);
T模板,不用问,当然是通用性最强的byte。
第一个参数,一般置0即可。
第二个参数,当然就是你要截取的矩形区域,你自己生成的纹理,位置的对应当然得自己掌握。
第三个参数,根据T的设定,自然是byte[]类型的数据缓冲区。需要注意,GetData对这个缓冲区的长度有着严格的要求——不能大也不能小。那我们如何来获得这个缓冲区长度呢?这里我推荐一条定律:原始纹理使用Xna中通用性最强的.png,则其被内容管道编译为.xnb且加载至Texture2D之后,刚刚好每个像素占4个字节(r,g,b,α)。于是,假定你截取的区域为50*10,则数组长度必然为50*10*4=2000.
第四个参数,数组的起始索引,为充分利用数组空间,当然置0.
第五个参数,元素个数,当然等于byte[]缓冲区的长度了。
SetData参数用法类似。
原理代码如下:
因为所有数据事先已经加载到内存之中,因此即使是即时生成新的目标纹理即时绘制,针对于人眼相对信息显示的感官要求而言,亦是绰绰有余的。
注意:提一个很外行的话题,千万不要试图从原始纹理中一个字一个字的截取出来,然后再一个字一个字的绘制上去。道理我不说,大家也应该懂。否则用上述方法就没什么意义了~
另,为进一步提高效率,我们应该避免反复的new、dispose(.net基本常识),大家可以提供一个缓存机制,即构建一个string到Texture2D的缓存映射即可。
如果你想知道有关Xna纹理字体的更多相关细节,以及如何自行生成一套Xna字体纹理,这里推荐几篇经典文章供大家参考:
>>> http://blogs.msdn.com/garykac/archive/2006/08/30/728521.aspx
>>> http://blogs.msdn.com/garykac/articles/732007.aspx
>>> http://www.angelcode.com/products/bmfont/
4.扩展content processor
此种方法是此次需要重点介绍的方法,也是笔者较为推荐的方法。
如下来自:
http://xna.omgsoft.com.cn/education/unicode_font_class.aspx (Xna游戏世界)
在XNA中显示中文字符或其它UNICODE字符(非GDI+)
XNA3.0+VS2008SP1下调试通过
由于XNA内置的DrawString方法并不能输出全角UNICODE字符,只能设定字符的起始和终止的内码,欧洲语系的字元不多,可以一次导入并生成字体,但像亚洲语系这样动辄上千的字元又是全角,好像设计者并没有考虑到这些情况。为了实现字符输出,已经有一些方法,例如利用.net中的GDI+。下面的实现方法是通过生成自定义的文字托管方式来实现的。
步骤如下:
建立字体文件
在当前项目中的“Content”中点击右键
加入新的文件,类型是"Sprite Font",起名为"DefaultFont.spritefont"
打开这个XML格式的文件,将"FontName"节中的字体改成含有目标语言字体的字体文件,这里使用“幼圆”
字典文件:
把游戏中需要的文字放到一个文本文件“message.txt”中,方便随时修改,以换行符结尾,内容如下: message.txt
中文输入测试,日本語テストを入力する
将这个文件放置在项目的Content目录下。
另存为一下这个文件,以“UTF-8”编码格式。
在解决方案浏览器中选择这个文件,在属性窗口的高级中的“生成操作”中选择“无”,“复制到输出目录”里选择“始终复制”。
文字处理类:
在解决方案浏览器中右键点击解决方案
添加新的项目,在项目类型对话框中选择"Windows Game Library(3.0)",起名"FontProcess"
在项目中增加引用,选择“Microsoft.Xna.Content.Pipeline”
将这个项目中的默认类"Class1.cs"改名为"DefaultFontProcessor.cs",修改为如下代码:
重新编译这个项目
添加项目引用
在本项目的Content下的"引用"上点击右键,添加项目引用,在弹出的对话框中选择刚才建立的项目:“FontProcessors”
在解决方案管理器选择本项目中的字体文件"DefaultFont.spritefont"
在属性窗口中的Content Processor中选择我们建立的处理类:"DefaultFontProssor"
在项目用使用
在我们的项目中使用如下代码:
或可参考:http://blog.csdn.net/sweetwxh/archive/2008/03/20/2199762.aspx
http://hi.baidu.com/wingde%BF%D5%BC%E4/blog/item/107643541e404dceb745aec9.html
http://www.cnblogs.com/aawolf/archive/2010/09/22/1833167.html
http://www.cnblogs.com/kenshincui/archive/2011/04/10/2011695.html
虽然如此,要实现Xna下的中文显示依然存在多种方法:
1.添加SpriteFont,修该他的CharacterRegion的Start和End,范围就是中文的Unicode范围。
因为通常大家不太好定位自己所需汉字的Unicode范围,而该范围又不允许无限制扩大,因此不可取~
2.GDI+
使用GDI+虽然能够满足中文显示的要求,但众所周知,GDI+本身的效率是个问题,因此,也不建议大家使用这种方法。
相关内容,请参考:http://www.cnblogs.com/XnaZero/archive/2009/03/29/1412148.html ,为XnaZero兄原创~
XNA3.0内带例子 SpriteFontX_1_0_2_1.rar
XNA3.1内带例子 SpriteFontX_1_0_2_1_For_Xna3_1.rar
XNA4.0内带例子 SpriteFontX_1_0_2_2_For_Xna4.rar
XNA支持中文输入示例 http://xna.omgsoft.com.cn/education/XNA_IME.aspx (Xna游戏世界)
作者没有开源,因此不太清楚内部机制,但个人猜想核心部分或许是这样的:
using System; using System.Drawing; using System.Drawing.Imaging; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System.IO; using AppColor = System.Drawing.Color; using XnaColor = Microsoft.Xna.Framework.Graphics.Color; namespace FontDemo { /// <summary> /// by kenkao(http://blog.csdn.net/kenkao) /// </summary> /// public class ChFont { static Graphics graphics; static GraphicsDevice graphicsDevice; static MemoryStream stream = new MemoryStream(); public ChFont(Game game) { graphics = Graphics.FromHwnd(game.Window.Handle); graphicsDevice = game.GraphicsDevice; } /// <summary> /// 生成中文纹理(by gdi+) /// </summary> /// <param name="graphicsDevice">图形设备</param> /// <param name="Text">文字</param> /// <param name="font">字体</param> /// <param name="FontColor">字体前景色</param> /// <returns>所得纹理</returns> public Texture2D CreateChFont(string Text, Font font, AppColor FontColor) { Texture2D ChTexture; try { //---生成字体 SizeF ef = graphics.MeasureString(Text, font); Bitmap bitmap = new Bitmap((int)ef.Width, (int)ef.Height); graphics = Graphics.FromImage(bitmap); graphics.DrawString(Text, font, new SolidBrush(FontColor), new PointF()); bitmap.Save(stream, ImageFormat.Png); //---注意:这里使用MemoryStream作为gid+与Xna的平行接口 stream.Seek(0L, SeekOrigin.Begin); ChTexture = Texture2D.FromFile(graphicsDevice, stream); //---不要妄图使用file,否则效率会非常令人纠结的^^ return ChTexture; } catch { return null; } } } }
调用方法生成中文纹理,而后使用SpriteBatch绘制即可~
3.字体纹理
相比以上两种方法而言,这种方法算是较为正统的Xna中文显示方法,借用Xna的ContentPipeline,这种方法的效率算是比较不错的。此种方法较为可取。
相关内容,请参考:http://kb.cnblogs.com/a/1459016/,为clayman兄原创~
其实要实现所谓的字体纹理,关键的核心方法有两个:
public class Texture2D : Texture { public void GetData<T>(T[] data); public void GetData<T>(T[] data, int startIndex, int elementCount); public void GetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount); public void SetData<T>(T[] data); public void SetData<T>(T[] data, int startIndex, int elementCount, SetDataOptions options); public void SetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount, SetDataOptions options); }
而追根究底,这两个方法实现的其实就是纹理间内存数据的拷贝而已。
整个方法原理如下:
1.准备好事先生成的“字库”(可以用Gdi+,好像还有一个开源的工具叫做ttf2bmp),其实就是带有通用中文字符的纹理。
2.程序启动时,通过内容管线,事先将其加载到内存,也就是一个Texture2D对象里。这里我们称作原始纹理。
3.需要绘制中文字符时,事先new一个空白的Texture2D。这里我们称作目标纹理。
4.根据字符的位置对应关系,从原始纹理中截取所要绘制的字符数据,赋值给目标纹理。
5.绘制目标纹理即可。
如上方法中,用到的其实也仅仅就是GetData与SetData。
其中需要注意的问题有两点:
1.生成的目标纹理,规格需要与原始纹理相同。
这里的规格,其实也就是指Texture2D构造函数中的【int numberLevels, TextureUsage usage, SurfaceFormat format】三个参数。那么如何来解决这个问题呢?其实很简单,从原始纹理中获取这三个属性,传入目标纹理的构造函数中即可。这样一来,目标纹理与原始纹理规格绝对相同。
不知是否有人要问,原始纹理的规格你如何获得?呵~ 这个你自然不用管,因为有Xna的内容管线替你完成~
2.使用GetData从原始纹理获取数据时,各个参数的确定问题。
我们获取数据,一般要用到此方法的第三个重载方法,即:
public void GetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount);
T模板,不用问,当然是通用性最强的byte。
第一个参数,一般置0即可。
第二个参数,当然就是你要截取的矩形区域,你自己生成的纹理,位置的对应当然得自己掌握。
第三个参数,根据T的设定,自然是byte[]类型的数据缓冲区。需要注意,GetData对这个缓冲区的长度有着严格的要求——不能大也不能小。那我们如何来获得这个缓冲区长度呢?这里我推荐一条定律:原始纹理使用Xna中通用性最强的.png,则其被内容管道编译为.xnb且加载至Texture2D之后,刚刚好每个像素占4个字节(r,g,b,α)。于是,假定你截取的区域为50*10,则数组长度必然为50*10*4=2000.
第四个参数,数组的起始索引,为充分利用数组空间,当然置0.
第五个参数,元素个数,当然等于byte[]缓冲区的长度了。
SetData参数用法类似。
原理代码如下:
/// <summary> /// by kenkao(http://blog.csdn.net/kenkao) /// </summary> /// int StringWidth; //字符串宽(目标纹理宽) int StringHeight; //字符串高(目标纹理高) Texture2D SurTexture; //原始纹理 Texture2D DesTexture; //目标纹理 SurTexture = Content.Load<Texture2D>("Font"); DesTexture = new Texture2D(graphics.GraphicsDevice, StringWidth, StringHeight, SurTexture.LevelCount, SurTexture.TextureUsage, SurTexture.Format);//生成与原始纹理相同规格的目标纹理 byte[] data = new byte[StringWidth * StringHeight * 4]; //生成数据缓冲区 //SurTexture.GetData获取原始数据 //……………… //DesTexture.SetData赋值 //……………… //绘制DesTexture即可
因为所有数据事先已经加载到内存之中,因此即使是即时生成新的目标纹理即时绘制,针对于人眼相对信息显示的感官要求而言,亦是绰绰有余的。
注意:提一个很外行的话题,千万不要试图从原始纹理中一个字一个字的截取出来,然后再一个字一个字的绘制上去。道理我不说,大家也应该懂。否则用上述方法就没什么意义了~
另,为进一步提高效率,我们应该避免反复的new、dispose(.net基本常识),大家可以提供一个缓存机制,即构建一个string到Texture2D的缓存映射即可。
如果你想知道有关Xna纹理字体的更多相关细节,以及如何自行生成一套Xna字体纹理,这里推荐几篇经典文章供大家参考:
>>> http://blogs.msdn.com/garykac/archive/2006/08/30/728521.aspx
>>> http://blogs.msdn.com/garykac/articles/732007.aspx
>>> http://www.angelcode.com/products/bmfont/
4.扩展content processor
此种方法是此次需要重点介绍的方法,也是笔者较为推荐的方法。
如下来自:
http://xna.omgsoft.com.cn/education/unicode_font_class.aspx (Xna游戏世界)
在XNA中显示中文字符或其它UNICODE字符(非GDI+)
XNA3.0+VS2008SP1下调试通过
由于XNA内置的DrawString方法并不能输出全角UNICODE字符,只能设定字符的起始和终止的内码,欧洲语系的字元不多,可以一次导入并生成字体,但像亚洲语系这样动辄上千的字元又是全角,好像设计者并没有考虑到这些情况。为了实现字符输出,已经有一些方法,例如利用.net中的GDI+。下面的实现方法是通过生成自定义的文字托管方式来实现的。
步骤如下:
建立字体文件
在当前项目中的“Content”中点击右键
加入新的文件,类型是"Sprite Font",起名为"DefaultFont.spritefont"
打开这个XML格式的文件,将"FontName"节中的字体改成含有目标语言字体的字体文件,这里使用“幼圆”
字典文件:
把游戏中需要的文字放到一个文本文件“message.txt”中,方便随时修改,以换行符结尾,内容如下: message.txt
中文输入测试,日本語テストを入力する
将这个文件放置在项目的Content目录下。
另存为一下这个文件,以“UTF-8”编码格式。
在解决方案浏览器中选择这个文件,在属性窗口的高级中的“生成操作”中选择“无”,“复制到输出目录”里选择“始终复制”。
文字处理类:
在解决方案浏览器中右键点击解决方案
添加新的项目,在项目类型对话框中选择"Windows Game Library(3.0)",起名"FontProcess"
在项目中增加引用,选择“Microsoft.Xna.Content.Pipeline”
将这个项目中的默认类"Class1.cs"改名为"DefaultFontProcessor.cs",修改为如下代码:
重新编译这个项目
DefaultFontProcessor.cs using System.IO; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Graphics; using Microsoft.Xna.Framework.Content.Pipeline.Processors; namespace FontProcessors { [ContentProcessor] public class DefaultFontProcessor : FontDescriptionProcessor { public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) { //载入文件 string fullPath = Path.GetFullPath("message.txt"); context.AddDependency(fullPath); string letters = File.ReadAllText(fullPath, System.Text.Encoding.UTF8); //导入字符 foreach (char c in letters) { input.Characters.Add(c); } return base.Process(input, context); } } }
添加项目引用
在本项目的Content下的"引用"上点击右键,添加项目引用,在弹出的对话框中选择刚才建立的项目:“FontProcessors”
在解决方案管理器选择本项目中的字体文件"DefaultFont.spritefont"
在属性窗口中的Content Processor中选择我们建立的处理类:"DefaultFontProssor"
在项目用使用
在我们的项目中使用如下代码:
Game1.cs using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace HelloWorld { public class GameMain : Microsoft.Xna.Framework.Game { private GraphicsDeviceManager graphics; private SpriteBatch spriteBatch; private SpriteFont font; public GameMain() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); font = Content.Load<SpriteFont>("DefaultFont"); } protected override void UnloadContent() { } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) { Exit(); } base.Update(gameTime); } protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); DrawString("中文输入测试,日本語テストを入力する", 50, 50); spriteBatch.End(); base.Draw(gameTime); } private void DrawString(String str, int x, int y) { spriteBatch.DrawString(font, str, new Vector2(x, y), Color.White); } } }
或可参考:http://blog.csdn.net/sweetwxh/archive/2008/03/20/2199762.aspx
http://hi.baidu.com/wingde%BF%D5%BC%E4/blog/item/107643541e404dceb745aec9.html
http://www.cnblogs.com/aawolf/archive/2010/09/22/1833167.html
http://www.cnblogs.com/kenshincui/archive/2011/04/10/2011695.html
相关文章推荐
- [转] [分享] WingIDE 彻底支持中文显示的方法
- Flask 让jsonify返回的json串支持中文显示的方法
- windows 2003 英文版支持中文显示、中文输入的设置方法
- 索爱模拟器支持中文显示修改方法
- 英文版windows 2003 SERVER支持中文显示、中文输入的设置方法
- [原创非首发]索爱k700模拟器支持中文显示修改方法
- 英文XP,支持中文显示的解决方法
- [分享] WingIDE 彻底支持中文显示的方法
- 让英文版Windows xp系统支持中文文字显示的方法介绍
- Win下Wing IDE 4.1支持中文显示的方法(修正方框乱码)
- Ubuntu CTRL+ALT+F1~F6 进入命令模式后不支持中文显示的解决办法
- Sublime Text 2支持GB2312和GBK,解决中文显示乱码问题
- SublimeText插件Pandoc导出PDF中文报错或者中文不显示解决方法
- 马宁的Windows Phone 7开发教程(4)——XNA显示中文字体
- php 五种数据加密可解密方法,部分还支持中文
- vim编辑器显示行号,语法高亮,自动缩进,支持方向键,backspace删除等设置方法
- vi/vim显示中文字符并且去掉^M的方法
- ASP.NET中文显示之两种解决方法
- Ubuntu下pdf、gedit、vim 中文无法读取或者显示乱码的解决方法
- apache Web服务器中文网页显示乱码的解决方法