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 阅读次数:7275