6.制作XNA乒乓1-游戏状态管理和中文支持
前一个教程已经完成了一个基本的2D游戏引擎,下面让我们使用这个引擎制作一个小游戏XNA乒乓,这个游戏来自于《ProfessionalXNA》中的第一个游戏,这也是我玩过的第一个游戏,好像还是初中时,邻居拿来一个盒子,将一个夹子夹在我家9寸黑白电视机的天线上,就可以用一个旋钮控制乒乓板的上下移动,现在看来很简陋,但当时玩得是如痴如醉,连饭也顾不得吃,在《机器人总动员》中又一次看到wall-E无聊地把电脑打了个7999比0,无限感慨。
好了,言归正传。首先,直接在引擎中编写代码不很恰当,好的做法是在解决方案管理器中新建一个项目,我起的名称叫Sample01,然后添加对引擎项目的引用,之后对Sample01项目中的Game1类从引擎类继承,代码如下:
namespace Sample01 { /// <summary> /// 游戏主类,从引擎继承 /// </summary> public class Game1:StunXnaGE { /// <summary> /// 用于变暗背景的图像 /// </summary> Texture2D blankTexture; /// <summary> /// 用于标题的字体 /// </summary> SpriteFont fontTitle; /// <summary> /// 用于菜单的字体 /// </summary> SpriteFont fontMenu; public Game1() { } /// <summary> /// 获取用于变暗背景的图像 /// </summary> public Texture2D BlankTexture { get { return blankTexture; } } /// <summary> /// 获取用于标题的字体 /// </summary> public SpriteFont FontTitle { get { return fontTitle; } } /// <summary> /// 获取用于菜单的字体 /// </summary> public SpriteFont FontMenu { get { return fontMenu; } } protected override void Initialize() { base.Initialize(); //加载游戏中用到的 blankTexture = Content.Load<Texture2D>("Textures\\blank"); fontTitle = Content.Load<SpriteFont>("Fonts\\fontTitle"); fontMenu = Content.Load<SpriteFont>("Fonts\\fontMenu"); //添加背景、主菜单屏幕 SceneManager.AddScene(new BackgroundScreen(this)); SceneManager.AddScene(new MainMenuScreen(this)); } protected override void LoadContent() { base.LoadContent(); } protected override void UnloadContent() { base.UnloadContent(); } protected override void Update(GameTime gameTime) { base.Update(gameTime); // 如果applyDeviceChanges为true则重新设置图形设备 if (applyDeviceChanges) { GameSettings gameSettings = SettingsManager.Read(); Graphics.PreferredBackBufferHeight = gameSettings.PreferredWindowHeight; Graphics.PreferredBackBufferWidth = gameSettings.PreferredWindowWidth; Graphics.IsFullScreen = gameSettings.PreferredFullScreen; Graphics.ApplyChanges(); applyDeviceChanges =false ; } //更新声音 Sound.Update(); } protected override void Draw(GameTime gameTime) { base.Draw(gameTime); } /// <summary> /// 绘制透明的黑色全屏图像,用于屏幕的淡入和淡出,将弹出屏幕后的背景变暗 /// </summary> public void FadeBackBufferToBlack(int alpha) { Viewport viewport = GraphicsDevice.Viewport; spriteBatch.Begin(); spriteBatch.Draw(BlankTexture, new Rectangle(0, 0, viewport.Width, viewport.Height), new Color(0, 0, 0, (byte)alpha)); spriteBatch.End(); } } }
其中需要说明的就是SettingsManager类,这个类可以读取游戏根目录下的一个xml文件: GameSettings.xml,设置屏幕的分辨率和是否全屏,当然,你也可以拓展这个文件,保存游戏得分,敌人数量等几乎所有游戏中要用到的设置,先看一下GameSettings.xml的内容:
<?xml version="1.0" encoding="utf-8" ?> - <GameSettings> <PreferredFullScreen>false</PreferredFullScreen> <PreferredWindowWidth>800</PreferredWindowWidth> <PreferredWindowHeight>600</PreferredWindowHeight> <EnableVsync>true</EnableVsync> - <KeyboardSettings> - <KeyboardSettings> <A>LeftControl</A> <B>S</B> <X>LeftShift</X> <Y>X</Y> <LeftShoulder>Space</LeftShoulder> <RightShoulder>None</RightShoulder> <LeftTrigger>None</LeftTrigger> <RightTrigger>None</RightTrigger> <LeftStick>Z</LeftStick> <RightStick>None</RightStick> <Back>Escape</Back> <Start>Enter</Start> <DPadDown>None</DPadDown> <DPadLeft>None</DPadLeft> <DPadRight>None</DPadRight> <DPadUp>None</DPadUp> <LeftThumbstickDown>Down</LeftThumbstickDown> <LeftThumbstickLeft>Left</LeftThumbstickLeft> <LeftThumbstickRight>Right</LeftThumbstickRight> <LeftThumbstickUp>Up</LeftThumbstickUp> <RightThumbstickDown>None</RightThumbstickDown> <RightThumbstickLeft>None</RightThumbstickLeft> <RightThumbstickRight>None</RightThumbstickRight> <RightThumbstickUp>None</RightThumbstickUp> </KeyboardSettings> </KeyboardSettings> </GameSettings>
这个游戏只用到了前三个数据项:默认不全屏,分辨率800*600,后面的选项没有用,以后制作键盘映射时会用到。 具体管理这个xml文件的是SettingsManager类,代码如下:
namespace Sample01 { [Serializable] public struct GameSettings { public bool PreferredFullScreen; public int PreferredWindowWidth; public int PreferredWindowHeight; public bool EnableVsync; } public static class SettingsManager { const string filename= "GameSettings.xml"; public static GameSettings Read() { // 打开文件 FileStream stream = File.Open(filename, FileMode.Open,FileAccess.Read); // 从文件中读取数据 XmlSerializer serializer = new XmlSerializer(typeof(GameSettings)); GameSettings data = (GameSettings)serializer.Deserialize(stream); // 关闭文件 stream.Close(); //返回获取的数据 return data; } public static void Save(GameSettings data) { // 打开文件 FileStream stream = File.Open(filename, FileMode.Create); // 将对象转换为XML数据并写到流中 XmlSerializer serializer = new XmlSerializer(typeof(GameSettings)); serializer.Serialize(stream, data); // 关闭文件 stream.Close(); } } }
这个类很简单,实现了保存和读取的功能,它来自于《BeginningXNA》第12章中的12.4.2 管理游戏设置,基本思路就是使用.NET自带的IO功能进行串行化和反串行化,缺点是只支持PC平台,要同时支持Xbox360,需要用到XNA自带的StorageContainer类,《ProfessionalXNA》中的赛车游戏就是这样做的,设置文件默认保存在“我的文档/SaveData”目录中。建议看看XNA帮助文档中Programming Guide→Storage中的所有文件,最后给出了一个异步调用的例子,而《ProfessionalXNA》中并没有实现异步调用功能,如果看一下《XNARecipes》中的1.9 将数据保存到文件,从文件读取数据,你会发现这个例子和帮助文件中的例子非常类似。
还有一个办法,就是编写自定义内容导入器,将xml文件导入到内容管道中,相关例子可见《XNARecipes》中的5.11 从XML文件加载数据。
中文支持
XNA 1.0 refresh版本之后提供了绘制文字的函数SpriteBatch.DrawString,具体的文字是保存在内容管道的spriteFont文件中的。但默认创建的spriteFont文件只支持英文字母,要支持中文,如果文字量少,第一种方法就是手动添加,例如spriteFont文件中的CharacterRegions元素中添加如下代码:
<CharacterRegions> <CharacterRegion> <Start> </Start> <End>~</End> <Start>好</Start> <End>好</End> </CharacterRegion> </CharacterRegions>
就可以显示“好”这个汉字。
如果要添加的中文很多,可以使用自定义内容管道,XNA帮助文档中的Programming Guide→Content Pipeline→How To: Extend the Font Description Processor to Support Additional Characters给出了具体实现方法,翻译可见如何扩展Font Description Processor支持附加的字符。 在Sample01项目的Content中添加对这个Font Description Processor的引用,别忘了在属性面板中将这个游戏使用的两个fontTitle,fontMenu文件的Content Processor从默认的Sprite Font Description - XNA Framework改为FontProcessor。
发布时间:2009/12/1 上午9:08:49 阅读次数:7147