调整和改编赛车游戏——游戏屏幕

游戏屏幕

赛车游戏中有很多不同的游戏屏幕,这些都是由RacingGame类中的gameScreens堆栈管理的。本节介绍游戏中使用的大部分屏幕和对应的功能。大多数游戏屏幕相当简单,但其他的有点复杂并实现了一个单元测试,通过单元测试能更好地了解这个类。例如,Credits屏幕是相当简单的,它只显示一个背景纹理,但主菜单很复杂并具有所有能进入另一个屏幕的按钮。Options屏幕介绍了许多新的控制选项,这些都要进行测试,这个类里有一个单元测试能帮你完成这个过程。

所有的游戏屏幕类都继承于IgameScreen接口(见图14-6),您也许还记得在第8章的Rocket Commander中也使用过。几乎没有改变,但更简单了。您现在只有一个叫做Render的方法,它没有参数并返回一个布尔值。该代码和你在XNA Shooter中使用的几乎一样。如果Render方法返回true意味着您可以返回到以前的游戏屏幕,一旦推出最后一个游戏屏幕则游戏推出。通常游戏屏幕返回false,因为玩家再次进入游戏屏幕后不会立即退出。

1
图 14-6

由于这个简单的接口,所以所有的游戏屏幕的类视图几乎是一样的,它们都只有一个Render方法。有些类还会有一些私有的辅助方法,但它们大多是非常简单的。一些更复杂的游戏屏幕还有单元测试用以测试是否所有内容和功能都能正确实行。处理整个游戏的GameScreen类是复杂的。不像XNA Shooeter或Rocket Commander,所有游戏代码的的处理和渲染是在Landscape和model类中的。游戏逻辑在Player类中被处理,这个有点复杂,但你已经在上一章学习了所有的CarPhysics类的基本物理知识和ChaseCamera类。

看看图14-7了解一下游戏屏幕的基本概况。最复杂的类显然是Mission类,它处理游戏过程和游戏逻辑。它不包含所有的游戏代码,有些是在Player类和RacingGame类中被处理的。

2
图 14-7

启动屏幕

启动屏幕(见图14-8)是较容易的一个类,它只是等着玩家按下手柄上的Start。如果没有手柄,Space或Esc键或鼠标左键也可让玩家继续。这个类唯一令人感兴趣的地方就是让“Press Start to continue”文字闪烁的代码。

3
图 14-8

/// <summary>
/// Render splash screen
/// </summary>
public bool Render()
{// This starts both menu and in game post screen shader!BaseGame.UI.PostScreenMenuShader.Start();// Render background and black barBaseGame.UI.RenderMenuBackground();BaseGame.UI.RenderBlackBar(352, 61);// Show Press Start to continue.if ((int)(BaseGame.TotalTime / 0.375f) % 3 != 0)BaseGame.UI.Logos.RenderOnScreen(BaseGame.CalcRectangleCenteredWithGivenHeight(512, 352 + 61 / 2, 26, UIRenderer.PressStartGfxRect),UIRenderer.PressStartGfxRect);// Show logosBaseGame.UI.RenderLogos();// Clicking or pressing start will go to the menureturn Input.MouseLeftButtonJustPressed ||Input.KeyboardSpaceJustPressed ||Input.KeyboardEscapeJustPressed ||Input.GamePadStartPressed;
} // Render()

RenderMenuBackground方法有点复杂。它用来显示菜单背景,即显示出汽车通过一条赛道。汽车是由计算机控制的而相机只是跟随它。代码不是很复杂:

// [From RenderMenuTrackBackground(), which is called by
// RenderMenuBackground(), both located in the UIRenderer class]// [Some code to calculate carPos, carMatrix, etc.]// Put camera behind car
RacingGame.Player.SetCameraPosition(carPos + carMatrix.Forward * 9 - carMatrix.Up * 2.3f);// For rendering rotate car to stay correctly on the road
carMatrix =Matrix.CreateRotationX(MathHelper.Pi / 2.0f) *Matrix.CreateRotationZ(MathHelper.Pi) *carMatrix;RacingGame.Landscape.Render();
RacingGame.CarModel.RenderCar(randomCarNumber, randomCarColor, carMatrix);

借助于Landscape类的Render方法和Model类的RenderCar方法您不必担心渲染场景、赛道或其他东西。相机矩阵可以确保你在正确的位置上观看,而赛车通过汽车矩阵在赛道上行驶。.

所有其他游戏屏幕菜单也使用RenderMenuBackground方法显示屏幕背景,但在一些游戏屏幕上不太明显,因为你把一个较暗的纹理放在前面(例如,在Credits屏幕上很难看到背景)。这只是一个背景效果,当你正式开始玩游戏时你可以看到更多的屏幕。

主菜单

主菜单(见图14-9)比其他菜单屏幕复杂点,但即使这样这个类也只有约250行代码。除了启动屏幕,其他屏幕都是从这里开始的。最重要的选项是开始游戏和观看highscores (头两个按钮)。

4
图 14-9

这个类最酷的功能是菜单按钮的动画。每个按钮获得一个介于0和1之间的浮点值,其中0代表按钮尺寸的最小可能值而1代表最大。当鼠标悬浮或用手柄、键盘选择按钮时,它将慢慢变大直到达到1.0。当你离开按钮,它又缓慢变小。

第一个按钮初始设为1,其他按钮设为最小尺寸(0)。

/// <summary>
/// Current button sizes for scaling up/down smooth effect.
/// </summary>
float[] currentButtonSizes =new float[NumberOfButtons] { 1, 0, 0, 0, 0, 0 };

然后在Rnnder方法中处理按钮选择和缩放。为了确保你会在同时悬浮在一个以上的按钮,这里为鼠标使用了一个辅助变量。如果不使用鼠标选取菜单按钮,这个变量将不会被使用。

// Little helper to keep track if mouse is actually over a button.
// Required because buttons are selected even when not hovering over
// them for GamePad support, but we still want the mouse only to
// be applied when we are actually over the button.
int mouseIsOverButton = -1;// [a little later in the code ...]
for (int num = 0; num < NumberOfButtons; num++)
{// Is this button currently selected?bool selected = num == selectedButton;// Increase size if selected, decrease otherwisecurrentButtonSizes[num] +=(selected ? 1 : -1) * BaseGame.MoveFactorPerSecond * 2;if (currentButtonSizes[num] < 0)currentButtonSizes[num] = 0;if (currentButtonSizes[num] > 1)currentButtonSizes[num] = 1;// Use this size to build rectRectangle thisRect =InterpolateRect(activeRect, inactiveRect, currentButtonSizes[num]);Rectangle renderRect = new Rectangle(xPos, yPos - (thisRect.Height - inactiveRect.Height) / 2,thisRect.Width, thisRect.Height);BaseGame.UI.Buttons.RenderOnScreen(renderRect, ButtonRects[num],// Make button gray if not selectedselected ? Color.White : new Color(192, 192, 192, 192));// Add border effect if selectedif (selected)BaseGame.UI.Buttons.RenderOnScreen(renderRect,UIRenderer.MenuButtonSelectionGfxRect);// Also check if the user hovers with the mouse over this buttonif (Input.MouseInBox(renderRect))mouseIsOverButton = num;// [etc.]
} // for (num)if (mouseIsOverButton >= 0)selectedButton = mouseIsOverButton;

Game Screen

GameScreen类(见图14-10)是最重要的游戏屏幕,因为它处理整个游戏逻辑。游戏变量不储存在这个类,但所有的重要组成部分(场景,赛道,汽车,对象,HUD等)从这里被渲染和调用。

5
图 14-10

大多数玩家变量都存储在Player类,所有的输入和物理在Player的基类中(CarPhysics和ChaseCamera)处理。Player类还使用了所有的游戏变量比赛。大多数变量显示在用户界面中,比如在HUD上的目前的游戏时间,它们在Player类的HandleGameLogic方法中被更新。

所有Render方法,包括HUD,都在UIRenderer辅助类中处理,其余的在Landscape类和model类中处理和渲染,阴影映射也在那里进行。所有的渲染和游戏处理是从这里调用,所以这个类为您提供了游戏中发生了什么的一个很好的概括。如果你编写一个改编版本,那么从这开始修改代码。在这或调用方法中注释掉代码,能很快地看到游戏的哪一部分受到了影响。

Render方法的第一部分处理所有的阴影映射,这不是很复杂,因为大多数已在Landscape类中被处理了。你只需将数据提供给阴影映射类,这个类渲染所有阴影映射,这些阴影映射能直接被使用。

/// <summary>
/// Render game screen. Called each frame.
/// </summary>
public bool Render()
{
if (BaseGame.AllowShadowMapping)
{// Generate shadowsShaderEffect.shadowMapping.GenerateShadows(delegate{RacingGame.Landscape.GenerateShadow();RacingGame.CarModel.GenerateShadow(RacingGame.Player.CarRenderMatrix);});// Render shadowsShaderEffect.shadowMapping.RenderShadows(delegate{RacingGame.Landscape.UseShadow();RacingGame.CarModel.UseShadow(RacingGame.Player.CarRenderMatrix);});
} // if (BaseGame.AllowShadowMapping)

然后开始post-screen glow shader并渲染所有的3D内容。这包括天空盒,带有赛道的场景和所有三维模型,最后是汽车。

// This starts both menu and in game post screen shader!
BaseGame.UI.PostScreenGlowShader.Start();// Render background sky and lensflare.
BaseGame.UI.RenderGameBackground();// Render landscape with track and all objects
RacingGame.Landscape.Render();// Render car with matrix we got from CarPhysics
RacingGame.CarModel.RenderCar(RacingGame.currentCarNumber, RacingGame.CarColor,RacingGame.Player.CarRenderMatrix);// And flush all models to be rendered
BaseGame.MeshRenderManager.Render();

在MeshRenderManager渲染所有的三维模型后您可以添加阴影映射效果。这里的调用顺序是重要的,因为如果在显示阴影前还没有渲染三维模型,阴影将不正确或不工作。

// Show shadows we calculated above
if (BaseGame.AllowShadowMapping)
{ShaderEffect.shadowMapping.ShowShadows();
} // if (BaseGame.AllowShadowMapping)// Apply post screen shader here before doing the UI
BaseGame.UI.PostScreenGlowShader.Show();

代码的最后是游戏的用户界面,如果你想去除或改变HUD,在这里做这件事。

// Play motor sound
Sound.UpdateGearSound(RacingGame.Player.Speed,RacingGame.Player.Acceleration);// Show on screen UI for the game.
BaseGame.UI.RenderGameUI((int)RacingGame.Player.GameTimeMiliseconds,// Best time and current lap(int)RacingGame.Player.BestTimeMs,RacingGame.Player.CurrentLap+1,RacingGame.Player.Speed * CarPhysics.MeterPerSecToMph,// Gear logic with sound (could be improved ^^)1+(int)(5*RacingGame.Player.Speed/CarPhysics.MaxSpeed),// Motormeter0.5f*RacingGame.Player.Speed/CarPhysics.MaxSpeed +// This could be improved0.5f*RacingGame.Player.Acceleration,RacingGame.Landscape.CurrentTrackName,Highscore.GetTop5Highscores());if (Input.KeyboardEscapeJustPressed ||Input.GamePadBackJustPressed)
{// Stop motor soundSound.StopGearSound();// Play menu music againSound.Play(Sound.Sounds.MenuMusic);// Return to menureturn true;
} // if (Input.KeyboardEscapeJustPressed)return false;
} // Render()
Highscores

Highscores屏幕(见图14-11)非常相似与Rocket Commander的,但所有在线highscores被移除,因为没有实现网络代码或Web服务。原因仍是XNA缺乏网络支持,但在PC版本中仍有可能实现。

6
图 14-11

在Highscores类中有几个辅助方法,例如,帮助您确定当前在游戏中的排名,但大多数方法已经这本书的前面几个游戏中用到过了。

下面的代码是用来显示排行榜前10名的玩家。你会发现,借助于UIRenderer类中的辅助方法代码是很简单的。如果您只想测试Highscores游戏屏幕,请使用类内部的单元测试,这是用来定位所有的用户界面元素的,此游戏的其他屏幕也以同样的方式做这件事。我也在Visual Studio 2005使用了TestDriven.NET,它能通过热键重新运行测试。这样我可以测试代码,按下热键,说:“哦,不,”,按下Escape,并修复代码,直到类工作正常。大多数的UI代码都是通过这种方式进行测试的。

// Go through all highscores
for (int num = 0; num < NumOfHighscores; num++)
{// Show player in white if mouse is over line or else use gray colorRectangle lineRect = new Rectangle(0, yPos, BaseGame.Width, lineHeight);Color col = Input.MouseInBox(lineRect) ?Color.White : new Color(200, 200, 200);// Fill in text for this lineBaseGame.UI.WriteText(xPos1, yPos, (1 + num) + ".", col);BaseGame.UI.WriteText(xPos2, yPos,highscores[selectedLevel, num].name, col);BaseGame.UI.WriteGameTime(xPos3, yPos,highscores[selectedLevel, num].timeMs, Color.Yellow);yPos += lineHeight;
} // for (num)

剩下的其他游戏屏幕类是Option,Help和Credit。它们和highscores类非常相似,并不令人兴奋。Option有一些不错的UI功能,可以让你在Input类的帮助下输入文字,选取其中一个或多个滑块并拖动它们。使用Option类的单元测试更多地了解这些功能。Help和Credit类只是在屏幕上显示一个纹理,非常类似于你先前看到的SplashScreen类。

最后,点击退出按钮可以退出游戏,因为主菜单关闭后将不会有其他游戏屏幕了。而所有其他游戏屏幕总是返回到主菜单(包括SplashScreen类)。

转载于:https://www.cnblogs.com/AlexCheng/archive/2010/10/17/2120185.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380853.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

trie树--详解

MiYu原创, 转帖请注明 : 转载自 ______________白白の屋 文章作者&#xff1a;yx_th000 文章来源&#xff1a;Cherish_yimi (http://www.cnblogs.com/cherish_yimi/) 转载请注明&#xff0c;谢谢合作。关键词&#xff1a;trie trie树 数据结构前几天学习了并查集和trie树&am…

yii mysql gii_Yii Gii使用

准备数据库第1步 - 创建一个新的数据库。数据库可以通过以下两种方式进行。在终端运行 mysql -u root –p登录数据后&#xff0c;通过执行 CREATE DATABASE mystudy CHARACTER SET utf8 COLLATE utf8_general_ci; 创建一个新的数据库;第2步 - 在 config/db.php 文件中配置数据库…

通过OracleDataReader来读取BLOB类型的数据 (转载)

通过OracleDataReader来读取BLOB类型的数据 在实际的应用过程中&#xff0c;需要把大块的二进制数据存储在数据库中。读取这些大块的数据&#xff0c;可以通过强制类型转换成为byte数组&#xff0c;但是当这个二进制数据体够大时&#xff08;几十兆或者上百兆&#xff09;&…

xampp启动Apache端口被占用,修改端口

apache启动端口被占用有可能是80端口被占用&#xff0c;也用可能是443端口被占用。修改这两个端口方法如下&#xff1a; 首先打开xampp&#xff0c;点击下图的config 如果是80端口被占用&#xff0c;选择httpd,conf,会自动打开这个文件&#xff0c;然后在文件里查找80 找到以…

Microsoft SharePoint Server 2010 的新增功能

Microsoft SharePoint Server 2010 包括几个关键的增强和新增功能。重新设计的用户界面中的功能区通过将命令放置到更易于导航的基于任务的选项卡上&#xff0c;来帮助您更快地完成工作。可以跨多个 Internet 浏览器工作&#xff0c;例如 Microsoft Internet Explorer 7.0 和 8…

php四种定界符

1.标准风格 <?php//代码 ?>2.短标记风格 <?//代码 ?>默认情况下是不可以这样写的&#xff0c;我们要到php.ini文件里修改一个配置 找到php.ini文件,我用的是xampp,所以就是以他为例&#xff0c;其他找到php.ini文件方法百度一下就知道了 点击Apache的config&…

php中文乱码问题

访问我的php文件&#xff0c;出现了乱码 解决方法如下&#xff1a; 方法1&#xff1a;加上meta标签&#xff0c;设置字符格式 例如&#xff1a; <?phpecho <meta charset"utf-8">;echo "小河流水人家"; ?>访问就不会乱码了&#xff0c;注…

java 文件转换字符串_java字符串文件互相转换

Java字符串与文件的互转Java中有时候需要读取一个文本类的文件,将其转换为字符串&#xff0c;然后做进一步处理。Java中没有现成的API方法&#xff0c;自己手动实现一个&#xff0c;大家来分享。一、字符串转换为文件/*** 将字符串写入指定文件(当指定的父路径中文件夹不存在时…

php中的echo、print,print_r、var_dump

我们用代码的运行结果来说明 1、echo <?phpheader(content-type:text/html;charsetutf-8);echo "小河流水人家",<br>;echo 10,<br>;echo true,<br>;echo false,<br>;echo array(8),<br>; ?>运行结果 可以输出字符串和数字…

风雨20年:我所积累的20条编程经验 (转)

风雨20年&#xff1a;我所积累的20条编程经验 (转) 编者按&#xff1a;原文作者乔纳森丹尼可&#xff08;Jonathan Danylko&#xff09;是一位自由职业的web架构师和程序员&#xff0c;编程经验已超过20年&#xff0c;涉足领域有电子商务、生物技术、房地产、医疗、保险和公用事…

php的变量、传值、传址、销毁变量

在php中&#xff0c;php的语句需要以**;**结尾&#xff0c;而且变量区分大小写&#xff0c;但关键字不区分大小写 1、变量的命名规则 变量必须以$开头&#xff0c;比如$name&#xff0c;$不是变量名的一部分&#xff0c;仅表示变量名的开始除了$以外&#xff0c;以字母、下划…

php的超全局变量

php的超全局变量如下图 所有的超全局变量都是数组类型&#xff0c;并且php已经帮我们定义好了&#xff0c;下面重点介绍几个 $_GET:用来保存get方式提交的数据 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>测试$_GET…

cmd运行php文件以及环境配置出现的问题、 php.exe不是内部或外部命令,也不是可运行的程序 或批处理文件、PHP startup: Unable to load dynamic library

我用php.exe远行php文件出现了几个问题&#xff0c;先说一下怎么解决这些问题的&#xff0c;然后再说怎么运行 首先是出现 ‘php.exe’ 不是内部或外部命令,也不是可运行的程序 或批处理文件&#xff0c;查了一下&#xff0c;是没有配置php环境变量&#xff0c;配置php环境的过…

php定义常量、判断有没有被定义、预定义常量、显示所有常量

常量一旦被定义&#xff0c;在脚本的其他任何地方都不能被改变&#xff0c;注意&#xff1a;常量名的前面没有$ 语法&#xff1a;define(name,value,case_insensitive ) name:常量名&#xff0c;一般常量名都大写value&#xff1a;常量值case_insensitive &#xff1a;bool类型…

java server模式 设置_JVM client模式和Server模式的区别

这里向大家描述一下JVM client模式和Server模式两者的区别和联系&#xff0c;JVM如果不显式指定是-Server模式还是-client模式&#xff0c;JVM能够根据下列原则进行自动判断(适用于Java5版本或者Java以上版本)。JVM client模式和Server模式JVM Server模式与client模式启动&…

PHP的数据类型、浮点型比较

在介绍php的数据类型前&#xff0c;先说一说强数据类型和弱数据类型。 弱数据类型&#xff1a;变量的类型取决于存放值的类型 强数据类型&#xff1a;变量的类型取决于申明变量时的类型。比如申明变量是A类型就不能存放B类型 PHP是弱数据类型&#xff0c;php支持8种原始数据类型…

《测试驱动开发》读书笔记

最终目标是整洁可用的代码 我们不是从建立对象开始&#xff0c;而是从测试开始 了解需求-》设计测试 -》让测试通过 列出所有已知问题&#xff0c;然后一个一个解决&#xff1b; 培养将软件开发化为一小步一小步开发任务的能力 测试程序与代码所存在的问题不在于重复设计&#…

puppeteer api_使用Node.js和Puppeteer API生成PDF文件

puppeteer apiPuppeteer is a Node library developed by Google and provides a high-level API for developers. Puppeteer是Google开发的Node库&#xff0c;并为开发人员提供了高级API。 With Node.js already up and running, we will install puppeteer via NPM (node pa…

php中进制转换

我们知道&#xff0c;进制有二进制、八进制、十进制、十六进制&#xff0c;但在php中只能存取八进制、十进制、十六进制 在讲进制转换之前&#xff0c;我们先说一下进制单词的缩写&#xff1a; 二进制&#xff1a;bin八进制&#xff1a;oct十进制&#xff1a;dec十六进制&…

python rgb 图像_在Python中查找RGB图像的互补图像

python rgb 图像Complementary image is a transformed image such that it consists of complementary colours of the ones, which is present in the original image. 互补图像是一种变换后的图像 &#xff0c;它由原始图像中存在的互补色组成。 For finding the complemen…