热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

输入和用户界面——游戏屏幕

游戏屏幕在图10-2你已经看到了一个简单的主菜单的例子,但您的游戏包含的不仅仅是游戏屏幕和菜单。您通常还需要一个credit屏幕让你出名,有一个Opti

游戏屏幕

在图10-2你已经看到了一个简单的主菜单的例子,但您的游戏包含的不仅仅是游戏屏幕和菜单。您通常还需要一个credit屏幕让你出名,有一个Option屏幕让用户轻松设置所有设置和更改屏幕分辨率,最好还有一个Help屏幕解释游戏的基本规则(见图10-3)。

1
图 10-3

大多数游戏屏使用一个特殊的背景纹理把大多数的信息显示在屏幕上。在任务选择画面,您可以选择四项任务中的其中一个,然后启动游戏。其他屏幕只是显示出一些信息和只有在Option屏幕上允许用户可以一些东西。所有的游戏画面在按下Back键后返回主菜单。

你使用游戏屏幕堆栈自动处理所有游戏屏幕上(见图10-4)。这可以让你使用更复杂的多层次的菜单系统,并可以随时返回以前的画面。如果你想返回到主菜单,只需移除堆栈中除最后一个以外的所有项。另一个我经常使用的技巧是在主菜单前添加另一个屏幕,当用户退出游戏时显示“购买这个游戏”屏幕。这个类本身只有几行代码,你只需在主类中添加一行额外的代码。大多数游戏屏幕类也非常简单。

2
图 10-4

为什么游戏屏幕堆栈很好?因为您需要做的就是从IgameScree接口继承得到到所有的游戏屏幕类(见图10-5),然后您可以使用下面的代码自动渲染和处理屏幕了。每个游戏屏幕类的Render方法会在推出此屏幕时返回true,这样将返回到前一个屏幕。当所有游戏屏幕都被移除则退出游戏。

3
Figure 10-5

// No more game screens?
if (gameScreens.Count == 0)
{// Then quitExit();return;
} // if (gameScreens.Count)// Handle current screen
if (gameScreens.Peek().Render())
{// Play sound for screen backSound.Play(Sound.Sounds.ScreenBack);gameScreens.Pop();
} // if (gameScreens.Peek)

帮助屏幕

作为一个非常简单的例子,下面是GameScreens命名空间下的Help类的完整代码。其他游戏屏幕类也不复杂,除了Mission类,它要负责处理整个游戏。

///


/// Help
///

class Help : IGameScreen
{#region Properties/// /// Name of this game screen/// /// Stringpublic string Name{get{return "Help";} // get} // Name#endregion#region Run/// /// Run game screen. Called each frame./// /// Form for access to asteroid managerpublic bool Run(RocketCommanderGame game){// Render backgroundgame.RenderMenuBackground();// Show helper screen texturegame.helpScreenTexture.RenderOnScreen(new Rectangle(0,174 * BaseGame.Height / 768,BaseGame.Width,510 * BaseGame.Height / 768),new Rectangle(0, 0, 1024, 510));if (game.RenderMenuButton(MenuButton.Back,new Point(1024 - 210, 768 - 140)) ||Input.KeyboardEscapeJustPressed)return true;return true;} // Run(game)
} // class Help

就是这样。看起来很简单,不是吗?如果你想了解得更多,请自己看一下游戏屏幕类。有些类包含单元测试表明行为方式和使用情况。

游戏中的用户界面

在这一节我要你跟随以下步骤制作XNA Shooter的游戏用户界面。用户界面不是很复杂,但你会遇到几个问题。以下内容被显示在这个游戏中:

  1. 任务时间:分,秒显示你玩了多久
  2. 当前分数:你射击,击落,收集物品和武器获得分数
  3. 最高分:努力成为排名第一
  4. 您目前的生命值:如果完全失去,则死
  5. 当前使用的武器和可以投掷的电磁脉冲炸弹

图10-6显示使用下列纹理显示这些内容:

  • HudTop.png在屏幕上的最上面一栏,显示时间,分数和最高分
  • HudButtom.png在底部,显示生命值和当前武器
  • GameFont.png,您前几场游戏中已经使用过的游戏字体
  • NumbersFont.png,顶端部分的数字,看起来比默认字体更酷

4
图 10-6

一个新的类通过NumbersFont.png纹理去显示数字,归功于Texture类和RenderOnScreen方法,这不难。

NumbersFont.png纹理在NumbersFont类中处理,它与第4章的TextureFont类很像,但简单得多,因为你只需要11个矩形,0至9的10个数字和一个冒号显示时间。

private void RenderHud()
{// Render top hud parthudTopTexture.RenderOnScreenRelative4To3(0, 0,hudTopTexture.GfxRectangle);// TimeBaseGame.NumbersFont.WriteTime(BaseGame.XToRes(73), BaseGame.YToRes(8), (int)Player.gameTimeMs);// ScoreBaseGame.NumbersFont.WriteNumberCentered(BaseGame.XToRes(485), BaseGame.YToRes(8), Player.score);// HighscoreBaseGame.NumbersFont.WriteNumberCentered(BaseGame.XToRes(920), BaseGame.YToRes(8), Highscores.TopHighscore);// Render bottom hud partRectangle bottomHudGfxRect = new Rectangle(0, 24, 1024, 40);hudBottomTexture.RenderOnScreenRelative4To3(0, 768 - 40,bottomHudGfxRect);// HealthRectangle healthGfxRect = new Rectangle(50, 0, 361, 24);hudBottomTexture.RenderOnScreenRelative4To3(50, 768 - 31,new Rectangle(healthGfxRect.X, healthGfxRect.Y,(int)(healthGfxRect.Width * Player.health), healthGfxRect.Height));// Weapon and Emps!Rectangle weaponMgGfxRect = new Rectangle(876, 0, 31, 24);Rectangle weaponGattlingGfxRect = new Rectangle(909, 0, 27, 24);Rectangle weaponPlasmaGfxRect = new Rectangle(939, 0, 33, 24);Rectangle weaponRocketsGfxRect = new Rectangle(975, 0, 24, 24);Rectangle weaponEmpGfxRect = new Rectangle(1001, 0, 23, 24);TextureFont.WriteText(BaseGame.XToRes(606),BaseGame.YToRes(768 - 20) - TextureFont.Height / 3, "Weapon: ");// Show weapon icon!Rectangle weaponRect =Player.currentWeapon == Player.WeaponTypes.MG ? weaponMgGfxRect :Player.currentWeapon == Player.WeaponTypes.Gattling ?weaponGattlingGfxRect :Player.currentWeapon == Player.WeaponTypes.Plasma ?weaponPlasmaGfxRect : weaponRocketsGfxRect;hudBottomTexture.RenderOnScreenRelative4To3(715, 768 - 31, weaponRect);// And weapon nameTextureFont.WriteText(BaseGame.XToRes(717+weaponRect.Width),BaseGame.YToRes(768 - 20) - TextureFont.Height / 3,Player.currentWeapon.ToString());TextureFont.WriteText(BaseGame.XToRes(864),BaseGame.YToRes(768 - 20) - TextureFont.Height / 3, "EMPs: ");// Show emp icons if we have anyfor (int num = 0; num } // RenderHud()

这种解决办法在PC很好,但一旦你运行在Xbox 360上并在电视屏幕显示(在写RenderHud方法之前我就写了TestHud单元测试)上你会看到,HUD不是完全可见的,或者更糟,几乎看不到。

如果你从来没在一个需要连接到电视机的游戏平台上编写游戏,这可能是一个新的问题,因为在电脑显示器,您可以使用100%的可视面积,没有安全区域的概念。但对大多数电视屏幕,你看不到100%的屏幕,更多的是90%,这意味着约10%屏幕边界宽度和高度都是不可见的(见图10-7)。

5
Figure 10-7

你可能会问,为什么XNA不把所有东西都自动放到安全区域中去呢。因为这不是那么容易。电视机接收全部信号,并根据输入电缆和电视机的模式,你会看到不同的结果。下面是我已经遇到的情况:

  1. 通过VGA或DVI电缆连接的PC显示器,您可以看到100%
  2. 通过VGA电缆把Xbox 360连接到电脑显示器,您也能看到100%(如果分辨率不匹配则接近100%)
  3. Xbox 360连接到一个旧式SCART显示器,约92%可见
  4. Xbox 360连接到我的新戴尔24寸监视器(HDTV):约93%~95%可见(取决于分辨率)
  5. 一些旧电视机(据XNA文档和网上的信息)约80%~90%,但我从来没有见过80%的情况,这可能是最坏的情况

如你所见,在Xbox 360上不是正好是90%,不过不用担心。在不同的情况下结果可有很大差异,XNA框架和你的游戏也没法帮你自动检查。只有一点可以肯定的是,在电脑上100%的屏幕像素都是可见,这也就是为什么许多电脑游戏使用的边界显示用户界面元素和其他信息。如果你看一下Xbox 360游戏,你会发现,它们往往只有一个较简单的界面,也不在屏幕边缘放置信息。

你不能只是将HUD显示在90%的安全区域,因为如果使用者能看到更多区域就会发现画面有错误,因为90%区域外没有画面,如果用户看到得更少仍有以前同样的问题。在继续工作之前你应该停在这里,并重新考虑这一问题。如图10-6那样显示用户界面元素对Xbox 360游戏机来说不是个好主意。最好的解决办法是改变用户界面的图片,把他们放在安全区域里。图10-8显示了如何改变HUD的图片使之能适用两种显示情况:在PC上,您把他们在屏幕边界上;在Xbox 360,放在内部92%的区域 (在90%的安全区域仍可见,但如果只有85%或更少就很难看到,,但我从来没有见过这种最坏的情况,大多数电视机都能达到90%~95%)。

6
图 10-8

图10-9显示了最XNA Shooter游戏的最终屏幕布局。请查看Misson类中的RenderHud方法获取更多细节。它更好地适应了宽屏分辨率,在Xbox 360看上去很好,即使较小分辨率的电脑上看起来也不错。为了测试菜单和游戏屏幕可运行游戏项目示例,这个例子仍基于开始于第5章的XnaGraphicEngine项目,但你有一些新的升级过的类。

7
图 10-9

诀窍

以我的经验,在Xbox 360开发XNA游戏你必须记住几件事。在PC上这不是个大问题,但需要花额外一点时间让它们正常工作。一个主要的问题是,如果你只在PC编写游戏而最后才在Xbox 360上测试,很多事情可能出差错(.NET Compact Framework上性能不佳、UI元素屏幕边界上导致在一些电视上不可见或对Xbox 360手柄支持差,而手柄是Xbox 360游戏机最主要的输入设备等等)。如果你有兴趣,请到我的博客仔细关于这些问题的讨论。

  1. 测试,测试还是测试。这是最重要的技巧。不断编写单元测试在PC和Xbox 360平台上。我同时打开PC和Xbox 360两个项目(两者使用相同的文件,但我只开发PC解决方案,而Xbox 360的解决方案只用于部署和测试)。我的几乎所有类都有单元测试,类编写完我就不断地测试。
  2. 不要使用foreach循环,尤其是在渲染循环中。这可能听起来有点疯狂,因为这在PC平台上没关系,现在的CPU速度足够快,能够在每帧处理创建和删除成千上万的物体,大多数游戏甚至都不需要。但在compact framework中,你每开始一个foreach循环都将创建一个新的enumerator实例,会占用很多内存,不久之后就会有很多抛弃的对象,而这些对象系统必须自己收集。这可能需要一些时间并极大地降低游戏性能。在PC版本上可能会超过200帧,但您的Xbox 360版本会停留在30~40帧左右。避免每帧都建立新的数据,并避免foreach循环(只需用正常循环取代,往往只需一条额外的代码)可以让性能提高100%或更多。
  3. 在Arena Wars(我开发的第一个.NET游戏),我就从来没有在游戏中创建任何数据。所有的对象在任务之前就被创造好,重用他们(这没什么大不了,因为游戏规则不允许无限多的单元,你可以通过dead元创建新单元)。这种做法可以减少垃圾收集性能冲突,这种冲突在慢的电脑NET 1.1情况下可能发生。在以后的项目,我无需关心太多关于建立新物体的问题,我只是用简单的方式编码,因为单元测试能帮你迅速的解决问题,但在.NET Compact Framework情况中未必是最好的。对于XNA Shooter和XNA Racer,我确定大部分的游戏数据在每一关卡开始就被建立,在游戏中不会变化。这使得写代码容易得多,可以让重构变得更加自由,以改善整体设计和代码的执行速度。我建议你采用“clean code”,并在开始时就考虑优化,重要代码要更好的得到优化,不然在项目中很难被管理。归功于NET 2.0中垃圾收集的改进,重用现有对象和异常处理比以前好得多,而且我们今天还拥有快得多的计算机。
  4. 电视上的可见区域可能会产生问题。只要搜索一下Xbox 360游戏画面的截图,你会发现,GUI (图形用户界面)大多数PC游戏有很大不同。PC游戏界面往往在屏幕边界显示提示,小按钮,以及其他不那么重要的事情。如果在Xbox 360游戏机这样做UI元素会被截除。对于XNA Shooter我不得不返工所有的用户界面元素,因为他们不适合电视屏幕,把它们放在一个栏(如Windows任务栏)中是不切合实际,因为在PC和电视屏幕上有很大不同。所以我把所有的UI元素放在浮动栏中,将根据屏幕自动调整。

重要的是让重要的用户界面元素在此90%(或93%,如果你想更接近边缘)矩形之内。这意味着在1920×1080分辨率下只使用90%(1728×945),或在屏幕边缘5%左右的地方(x坐标:96,y坐标:54)绘制用户界面元素。这些像素的位置取决于屏幕分辨率,要在你的游戏主类中计算好,并利用它们绘制用户界面。

有关.NET Compact Framework、如何在Xbox 360上更好地使用XNA框架的更多知识,请阅读.NET Compact Framework小组写的以下文章,网址在http://blogs.msdn.com/netcfteam/archive/2006/12/22/managed-code-performance-on-xbox-360-for-the-xna-framework-1-0.aspx。

转:https://www.cnblogs.com/AlexCheng/archive/2010/08/17/2120238.html



推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • C# WPF自定义按钮的方法
    本文介绍了在C# WPF中实现自定义按钮的方法,包括使用图片作为按钮背景、自定义鼠标进入效果、自定义按压效果和自定义禁用效果。通过创建CustomButton.cs类和ButtonStyles.xaml资源文件,设计按钮的Style并添加所需的依赖属性,可以实现自定义按钮的效果。示例代码在ButtonStyles.xaml中给出。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有