UNITY 3D –游戏编程–第6部分(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/unity-d-game-programming-part-5-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 23 分钟阅读 - 11058 个词 阅读量 0UNITY 3D –游戏编程–第6部分(译文)
原文地址:https://www.codeproject.com/Articles/883396/UNITY-D-Game-Programming-Part-5
原文作者:Vahe Karamian
译文由本站 robot-v1.0 翻译
前言
The sixth article in a series to discuss Unity 3D and how to get started with your own 3D projects.
该系列的第六篇文章讨论Unity 3D以及如何开始自己的3D项目.
介绍(Introduction)
在本系列的第六部分中,我们将扩展在本系列的第五部分中开始的游戏理念.(In part six of the series, we will be expanding on the game idea we have started in Part 5 of the series.) 如果您尚未这样做,请花一点时间阅读:(If you have not already done so, please take a moment and read:)
-
Unity 3D –游戏编程–第6部分(Unity 3D – Game Programming – Part 6)
Unity 3D网络文章:(Unity 3D Networking Article(s):)
-
Unity 3D-网络游戏编程(Unity 3D - Network Game Programming) Unity 3D Leap Motion和Oculus Rift文章:(Unity 3D Leap Motion and Oculus Rift Article(s):)
-
Unity 3D-Leap Motion集成(Unity 3D - Leap Motion Integration) 在本系列的第一部分中,我们从Unity 3D环境的基础知识入手.感受一下IDE以及将在整个项目中使用的不同部分.我们还介绍了如何使用设计器中的工具将不同的变换应用于选定的游戏对象:定位,旋转和缩放.最后,我们研究了如何创建第一个脚本,并使用该脚本在多维数据集的Y轴上应用了旋转变换.(In the first part of the series we started by the very basics of the Unity 3D environment. Getting a feel of the IDE and the different sections which you will be working with throughout your project. We also covered how to use the tools in the designer to apply different transformation to a selected Game Object: positioning, rotation and scaling. We finally looked at how to create our first script and using the script apply a rotation transform on the Y-Axis of our cube.) 在本系列的第二部分中,我们研究了通过编码对给定对象进行的更多转换.我们还研究了如何创建对于场景中的对象渲染至关重要的光源.(In the second part of the series, we looked at more of the transformation of a given object through coding. We also looked at how to create light sources that are crucial for the rendering of your objects in the scene.) 在本系列的第三部分中,我们研究了如何通过键盘处理用户输入,并根据键码采取了特定的操作.(In the third part of the series we looked at how to process user input through the keyboard and based on the key code take particular actions.) 在本系列的第四部分中,我们着眼于创建一个简单的用户界面.我们开发的用户界面为我们提供了一种向用户反馈的方式,并且为用户提供了输入我们的游戏或模拟游戏的另一种方法.(In the fourth part of the series, we looked at creating a simple user interface. The user interface that we developed provided us a means to feedback to the user, and also another method for the user to input to our game or simulation.) 在第五部分,我们开始了一个简单游戏的想法.我们还研究了如何将3D模型导入游戏引擎.(In the fifth part, we started the idea of a simple game. We also looked at how to import 3D models into the game engine.) 在第6部分中,我们将扩展我们的游戏理念,并使之更有趣,更完整.(In Part 6, we will be expanding on our game idea and making it more interesting and more complete.)
游戏编程简介:使用C#和Unity 3D(Introduction to Game Programing: Using C# and Unity 3D*) (Paperback)*)(平装)( 要么(or*) (eBook)*)(电子书)( 是为帮助对计算机科学和游戏编程领域感兴趣的个人而设计和开发的.它旨在说明计算机编程的概念和基础.它使用简单游戏的设计和开发来说明和应用这些概念.(is designed and developed to help individuals that are interested in the field of computer science and game programming. It is intended to illustrate the concepts and fundamentals of computer programming. It uses the design and development of simple games to illustrate and apply the concepts.) [ ](http://www.lulu.com/commerce/index.php?fBuyContent=18159441) 书号:9780997148404(ISBN: 9780997148404) 版本:第一版(Edition: First Edition) 发行人:Noorcon Inc.(Publisher: Noorcon Inc.) 英语语言(Language: English) 274页(Pages: 274) 装订:装订完美的平装本(彩色)(Binding: Perfect-bound Paperback (Full Color)) 尺寸(英寸):6宽x 9高(Dimensions (inches): 6 wide x 9 tall) -
|
||电子书(ePUB)(eBook (ePUB))
书号(ISBN):9780997148428(ISBN: 9780997148428)
版本:第一版(Edition: First Edition)
发行人:Noorcon Inc.(Publisher: Noorcon Inc.)
英语语言(Language: English)
大小:9.98 MB(Size: 9.98 MB) |
---|
Windows Phone 8.x演示:(Windows Phone 8.x Demo:)
我提供了一个免费的电话应用程序,您可以在Windows Phone上下载和预览演示.要下载移动应用程序,请点击以下链接:(I have provided a free phone application that you can download and preview the demos on your Windows Phone. To download the mobile application, follow the link:) CodeProjectArticleSample(CodeProjectArticleSample)
代码项目文章示例移动应用(Code Project Articles Sample Mobile App)
文章代码和视觉效果的实时预览:(Live Preview of Article Code and Visuals:)
链接到实时预览:(Link to live preview:) http://www.noorcon.com/CodeProject/CodeProjectArticlePreview.html(http://www.noorcon.com/CodeProject/CodeProjectArticlePreview.html)
背景(Background)
**注意:(NOTE:)**对于这个粒子,我将使用SketchUp创建一些简单的构建基块,并将其导入到Unity中!我不是3D建模者或设计师,因此请耐心等待,请原谅!(For this particle, I will be using SketchUp to create some simple building blocks, which I will use to import into Unity! I am not a 3D Modeler or Designer, so please be patient and excuse the mess!) 假定本文的读者通常熟悉编程概念.还假定读者具有C#语言的理解和经验.还建议本文的读者也熟悉面向对象的编程和设计概念.我们将根据需要在本文中简要介绍它们,但是由于它们完全是单独的主题,因此我们将不对其进行详细介绍.我们还假设您有学习3D编程的热情,并且具有3D图形和矢量数学的基本理论概念.(It is assumed that the reader of this article is familiar with programming concepts in general. It is also assumed that the reader has an understanding and experience of the C# language. It is also recommended that the reader of the article is familiar with Object-Oriented Programming and Design Concepts as well. We will be covering them briefly throughout the article as needed, but we will not get into the details as they are separate topics altogether. We also assume that you have a passion to learn 3D programming and have the basic theoretical concepts for 3D Graphics and Vector Math.) 最后,本文使用Unity 3D版本4.6.1,这是截至初始发布日期的最新公共发行版.该系列中讨论的大多数主题都将与旧版本的游戏引擎兼容,也许还与应该在今年某个时候发布的新版本兼容.但是,有一个主题与当前版本的游戏引擎相比在当前4.6.1版本中有显着差异,那就是UI(用户界面)管道.这是由于引擎中的新UI架构远远优于我们在此版本之前所拥有的.首先,我对新的UI架构感到非常满意.(Lastly, the article uses Unity 3D version 4.6.1 which is the latest public release as of the initial publication date. Most of the topics discussed in the series will be compatible with older versions of the game engine, and perhaps also the new version which is supposed to be release sometime this year. There is however, one topics which is significantly different in the current 4.6.1 version compared to the older version of the game engine, and that is the UI (User Interface) pipeline. This is due to the new UI architecture in the engine which is far superior to what we had prior to this release. I for one, am very happy with the new UI architecture.)
使用代码(Using the code)
下载文章系列的项目/源代码:(Downloading the project/source code for article series:) 下载源(Download source) .(.) 随着每篇连续的文章的提交,项目/源代码也将不断扩展.新的项目文件和源文件将包括该系列中的较早部分.(With each consecutive article that is submitted, the project/source code will be also expanding. The new project files and source files will be inclusive of older parts in the series.) **注意:(NOTE:)**要获取最新代码,请转至该系列中最新发布的部分并下载代码.(To get the latest code, go to the most recent published part in the series and download the code.)
回顾想法(Recalling the Idea)
如果您回想起第5部分,我们就开始创建一个类似于迷宫的关卡.该级别必须足够大,以允许我们自由移动并与其中的其他对象进行交互.您可以返回第5部分,以查看摘要.(If you recall from Part 5, we started to create a level resembling a maze. The level had to be large enough to allow us to freely move and interact with other object within it. You can go back to Part 5 to review the brief.)
我使用SketchUp创建了以下模型,将其用作我们的关卡基础.(I used SketchUp to create the following model, which was used as our level base.)
图1-我的关卡的SketchUp模型(Figure 1-SketchUp Model for My Level) 然后我们介绍了(Then we introduced, the)角色播放器(CP)(Character Player (CP))以a表示(represented by a)领域(Sphere)原始的(primitive, and a)硬币(coin)修改后的对象(object represented by a modified)胶囊(Capsule)原始.(primitive.) 我们做了(We made our)CP(CP)可移动并转换为刚体,以便我们可以使用物理引擎和引擎提供的碰撞检测.我们还做了(movable and converted it to a rigid body so that we can use the physics engine and the collision detection provided by the engine. We also made the)硬币(coin)对象的(object’s)对撞机(Collider)组件被触发.(component be trigger.)
实施游戏(Implementing the Game)
从摘要中可以得知,我们希望能够在给定的时间范围内收集尽可能多的硬币.到目前为止,我们已经创建了游戏所需的主要GameObject.现在,我们需要开始考虑游戏的物流.(From the brief, we are told that we want to be able to collect as many coins as possible in a given time frame. We have thus far created the main GameObjects needed for our game. Now we need to start thinking about the logistics of our game.)
关于游戏设计和游戏玩法的思考(Thinking about the Game Design and Game Play)
每个游戏都有一些规则.这些规则是由游戏的设计者/开发者/建筑师定义和创建的.规则越复杂,设计和实现就越复杂.(Every game has some set of rules. These rules are defined and created by the designer / developer / architect of the game. The more sophisticated the rules, the more sophisticated the design and implementation.) 就我们而言,我们面前有一个非常简单的游戏,但尽管如此,我们仍然需要思考,定义和创建一组规则.例如,让我们看一下以下问题:(In our case, we have a very simple game in front of us, but nevertheless, we still need to think about and define and create a set of rules. For instance, let’s take a look at the following questions:)
-
您的硬币将如何放置在关卡中?(How will your coins be placed in the level?)
-
他们会在设计时手动放置吗?要么(Will they be placed manually at design time? Or)
-
它们会在运行时动态放置吗?(Will they be placed dynamically at runtime?)
-
-
他们会有寿命吗?那是:(Will they have a life-span? That is:)
-
它们会在游戏的整个过程中可用,还是直到玩家拿走为止?要么(Will they be available for the whole duration of the game, or until picked up by the player? Or)
-
它们会根据某种逻辑出现和消失吗?(Will they appear and disappear based on some logic?)
- 如果它们确实消失了,它们将如何重新出现?(If they do disappear, how will they reappear, or do they?)
-
-
每个硬币会具有相同的确切价值吗?(Will each coin have the same exact value?)
-
您的玩家将如何与硬币互动?(How will your player be interacting with the coins?)
- 您将如何保持得分?(How will you keep score?)
-
您的玩家将如何与关卡中的其他对象进行互动? (如果有)(How will your player be interacting with other objects in the level? (if any))
-
您的UI将显示给播放器什么?(What will your UI display to the player?)
-
收集的硬币数量?(Number of coins collected?)
-
当前的游戏运行时间?(Current run-time of the game?)
-
完成多少时间?(Amount of time to complete?)
-
让我们继续尝试回答其中的一些问题,并开始努力在我们的游戏中实现它们.(Let’s go ahead and try to answer some of these questions and start working towards implementing them in our game.) 为简单起见,让我们继续进行,并决定在设计时将硬币放置在关卡中.我们还可以为硬币分配一个随机值,以使其在游戏中更有趣.我们可以将硬币编程为具有1到9之间的随机值.现在,我们还可以决定硬币在整个游戏中具有完整的寿命.(For simplicity, let’s go ahead and decide that we will be placing our coins in the level at design time. We can also assign a random value to our coin to make it more interesting in the game. We can program the coins to have a random value between 1 and 9. For now, we can also decide that the coins will have a full lifespan throughout the game.) CP将通过碰撞与硬币对象进行交互.当玩家与硬币对象碰撞时,它将触发一个事件,该事件将捡起硬币并进行必要的计费,以增加玩家在游戏中的得分.(The CP will interact by the coin objects by collision. When the player collides with a coin object, it will trigger an event which will pick-up the coin and perform the necessary accounting to increase the player’s score in the game.) 玩家将有一个有限的时间来拾取尽可能多的硬币.(The player, will have a finite set of time to pick up as many coins as possible.)
实施我们的游戏(Implementing Our Game Play)
让我们继续前进,创建脚本,这将使我们的硬币更加生动.叫这个(Let’s go ahead and create the script which will give our coins some life. Let’s call this)Coin.cs(Coin.cs):(:)
using UnityEngine;
using System.Collections;
public class Coin : MonoBehaviour {
private int value;
public int VALUE
{
get{ return this.value; }
}
// Use this for initialization
void Start () {
this.value = Random.Range (1, 9);
}
// Update is called once per frame
void Update () {
}
}
该脚本在(This script defined in)**Coin.cs(Coin.cs)**将被附加到(will be attached to the)硬币(coin)目的.在游戏开始时,它将随机生成一个1到9之间的数字并将其放在value变量中.这将是整个游戏中硬币的价值.(object. At the start of the game it will randomly generate a number between 1 and 9 and place it in the value variable. This will be the value of the coin throughout the game.)
预制件(Prefabs)
通过添加组件并将其属性设置为适当的值,可以很方便地在场景中构建GameObject.但是,当您拥有诸如NPC,道具或风景之类的对象在场景中重复使用多次时,这可能会带来问题.简单地复制对象肯定会产生重复,但是它们都可以独立编辑.通常,您希望特定对象的所有实例都具有相同的属性,因此在场景中编辑一个对象时,您不希望不必对所有副本重复进行相同的编辑.(It is convenient to build a GameObject in the scene by adding components and setting their properties to the appropriate values. This can create problems, however, when you have an object like an NPC, prop or piece of scenery that is reused in the scene several times. Simply copying the object will certainly produce duplicates but they will all be independently editable. Generally, you want all instances of a particular object to have the same properties, so when you edit one object in the scene, you would prefer not to have to make the same edit repeatedly to all the copies.)
一种(A)预制件(Prefab)正是这样做的,并且由于我们需要创建我们的多个实例(does exactly that, and since we need to create multiple instances of our)硬币(Coin)GameObject,我们想创建一个(GameObject, we would like to create a)硬币(Coin)预制的.有几种方法可以创建(prefab. There are several ways to creating a)预制件(Prefab),我将向您展示一种超级简单的方法.(, I will show you one way that is supper easy.)
在你的(In your)项目窗口(Project Window)选择你的(select your)预制文件夹(prefab folder).拖放您的(. Drag and drop your)硬币(coin)来自的GameObject(GameObject from the)层次窗口(Hierarchy Window)进入(into the)项目窗口(Project Window)在下面(under the)预制文件夹(prefab folder).(.)
图2-显示硬币游戏对象的预制件的创建(Figure 2-Displaying Creation of a Prefab for the Coin GameObject)
预制件非常有用,我们将看到如何在更复杂的情况下更有效地使用它们.在此阶段,我们只想复制我们的对象,并能够通过穿透代码的设计者随时创建该对象的实例!(Prefabs are very useful and we will see how to use them more effectively in more complex scenarios. At this stage, we just want to make a copy of our object and be able to create instances of that object at any time, either through the designer of through code!)
让我们继续使用新创建的Prefab在关卡上放置一些硬币.我在场景中放置了大约8个硬币,并尝试将它们尽可能地排在网格上.下图是我所拥有的:(Let’s go ahead and use the newly created Prefab to place a few coins on the level. I have placed about eight coins in the scene, and tried to space them on the grid as much as possible. The following figure is what I have:)
图3场景中8种预制硬币的显示(Figure 3-Display of 8 Prefab Coins in the Scene) 出于演示目的,这应该可以使我们满意.现在,让我们看一下需要应用于(This should do us fine for the purposes of the demonstration. Now, let’s take a look at the code that needs to be applied to the)角色播放器(CP)(Character Player (CP))检测与(to detect a collision with the)硬币(Coin)目的.(object.) 这是到目前为止CP对象的清单:(Here is the listing so far for the CP object:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class playerInput : MonoBehaviour {
private int score; // internal score variable
public int SCORE
{
get{ return this.score; }
}
// Use this for initialization
void Start () {
this.score = 0;
}
// Update is called once per frame
void Update () {
// code for the movement of player (CP) forward
if(Input.GetKey(KeyCode.UpArrow)){
this.transform.Translate(Vector3.forward * Time.deltaTime);
}
// code for the movement of player (CP) backward
if(Input.GetKey(KeyCode.DownArrow)){
this.transform.Translate(Vector3.back * Time.deltaTime);
}
// code for the movement of player (CP) left
if(Input.GetKey(KeyCode.LeftArrow)){
this.transform.Rotate(Vector3.up, -5);
}
// code for the movement of player (CP) right
if(Input.GetKey(KeyCode.RightArrow)){
this.transform.Rotate(Vector3.up, 5);
}
}
// This event will be raised by object that have their Is Trigger attributed enabled.
// In our case, the coin GameObject has Is Trigger set to true on its collider.
void OnTriggerEnter(Collider c){
if(c.tag.Equals("coin")){
Coin coin = c.GetComponent<Coin>();
// increase score
this.score += coin.VALUE;
// remove the Coin object from the scene
Destroy(c.gameObject);
}
}
}
新的修改做了一些事情.首先,我们引入了一个变量来跟踪玩家的得分.然后在(The new modification does a few things. First we have introduced a variable to keep track of the score for the player. Then in the)OnTriggerEnter(对撞机c)(OnTriggerEnter(Collider c))函数,我们正在检查是否与硬币对象相撞,如果是,我们得到(function we are checking to see if we have collided with a coin object, and if so, we get the)硬币脚本组件(Coin Script Component)的(of the)硬币(Coin)对象并通过提取硬币的价值(object and extract the value of the coin through the)值(VALUE)属性.然后,我们将得分增加硬币的价值.然后我们要从场景中删除Coin对象,因此我们使用(property. Then we increment our score by the value of the coin. Then we want to remove the Coin object from the scene, hence we use the)销毁(c.gameObject)(Destroy(c.gameObject))功能从场景中销毁对象.(function to destroy the object from the scene.) 如果到目前为止您已按照说明进行操作,则在运行程序时将看到结果.(If you have followed with the instructions so far, when you run the program you will see the results.)
关于用户界面的思考(Thinking about the User Interface)
游戏级别的用户界面非常简单.我们只需要能够显示玩家的得分和计时器,以表明玩家需要多少时间才能达到自己的目标.(The user interface on the game level is very simple. We just need to be able to display the player’s score and a timer to indicate how much time the player has to meet his / her objectives.)
因为我们将本系列的第4部分专门介绍UI创建的基础知识,所以我将不介绍创建UI的步骤.(I will not be covering the steps for creating the UI since we dedicated Part 4 of the series to cover the basics of UI creation.)
首先,我想解决游戏的得分UI.下图显示了外观:(First I would like to tackle the scoring UI for the game. The following figure shows how it will look:)
图4评分界面(Figure 4-Score UI) 要创建得分界面,我使用了(To create the score UI, I used a)面板(Panel)固定在屏幕的左上角(that has been anchored to the top left corner of the screen, an)图片(Image)在显示硬币图标的面板中,以及(within the panel that displays the coin icon, and a)文本(Text)标签的元素.要获得自定义外观,您可以在面板的背景等上应用纹理.有关详细信息,请参阅第4部分.(element for the label. To get a custom look and feel, you can apply a texture to your panel’s background and etc… refer to Part 4 for details.) 现在,让我们为计时器做类似的事情.对于计时器,我使用了新的(Now, let’s do something similar for our timer. For the timer, I have used a new)面板(Panel)固定在屏幕的右上角,(anchored to the right top corner of the screen, and a)文本(Text)元素以显示计时器.(element to display the timer.) 目前,我对这个特定游戏的UI设计感到非常满意.因此,现在,我们需要确保我们的代码可以访问UI元素以进行相应的更新.(I am pretty happy with what I have as a UI design for this particular game at the moment. So now, we need to make sure our code has access to the UI elements to update them accordingly.) 我已经更新了(I have updated the)**playerInput.cs(playerInput.cs)**脚本如下:(script to the following:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class playerInput : MonoBehaviour {
public Text lblScore; // text UI element for displaying score
public Text lblTimer; // text UI element for displaying timer
private int score; // internal score variable
public int SCORE
{
get{ return this.score; }
}
private float timer; // variable to keep track of time
// Use this for initialization
void Start () {
this.score = 0;
this.timer = 30.00f;
// check to make sure labels are defined before updating
if (this.lblScore != null)
this.lblScore.text = this.score.ToString();
if (this.lblTimer != null)
this.lblTimer.text = string.Format("{0:F2}", this.timer - Time.time);
}
// Update is called once per frame
void Update () {
if (this.lblTimer != null)
this.lblTimer.text = string.Format("{0:F2}", this.timer - Time.time);
// code for the movement of player (CP) forward
if(Input.GetKey(KeyCode.UpArrow)){
this.transform.Translate(Vector3.forward * Time.deltaTime);
}
// code for the movement of player (CP) backward
if(Input.GetKey(KeyCode.DownArrow)){
this.transform.Translate(Vector3.back * Time.deltaTime);
}
// code for the movement of player (CP) left
if(Input.GetKey(KeyCode.LeftArrow)){
this.transform.Rotate(Vector3.up, -5);
}
// code for the movement of player (CP) right
if(Input.GetKey(KeyCode.RightArrow)){
this.transform.Rotate(Vector3.up, 5);
}
}
// This event will be raised by object that have their Is Trigger attributed enabled.
// In our case, the coin GameObject has Is Trigger set to true on its collider.
void OnTriggerEnter(Collider c){
if(c.tag.Equals("coin")){
Coin coin = c.GetComponent<Coin>();
// increase score
this.score += coin.VALUE;
// update score on the UI
if (this.lblScore != null)
this.lblScore.text = this.score.ToString();
// remove the Coin object from the scene
Destroy(c.gameObject);
}
}
}
我们在脚本中引入了一些变量:(We introduced a few variable in the script:)分数(lblScore),(,)**计时器(lblTimer)**和(, and)计时器(timer).我们更新了(. We updated the)开始()(Start())函数执行以下操作:初始化默认值(function to perform the following: initialize the default values for)得分了(score)和(and)计时器(timer),检查是否(, check to see if)**分数(lblScore)**和(and)**计时器(lblTimer)**不是null,如果不是,则将值分配给它们的text属性.(are not null, and if not, then assign the values to their text property.) 我们更新的下一个功能是(The next function we have updated is the)更新()(Update())功能.我们只包含了几行来为我们更新计时器字段.(function. We just included a couple of lines to update the timer field for us.) 最后更新的功能是(The last function that got updated was)OnTriggerEnter(对撞机c)(OnTriggerEnter(Collider c))功能.在检测到我们是否与(function. After detecting if we have collided with a)硬币(Coin)对象,我们提取硬币的价值并相应地提高玩家的得分.最后,(object, we extract the value of the coin and increment the player’s score accordingly. Finally,)**分数(lblScore)**得到更新以在用户界面上相应地反映分数.(gets updated to reflect the score accordingly on the user interface.)
进一步增强逻辑(Enhancing the Logic a Little More)
在结束本系列的第6部分之前,我还想进行一些其他增强.如果您注意到了,我们没有办法结束游戏!好吧,正如您所知,每场比赛都必须结束.因此,我们应该考虑如何触发游戏结束!(There are a few more enhancements that I would like to make before I end Part 6 of the series. If you notice, we don’t have a means of ending the game! Well, as you know every game has to come to an end. Therefore, we should think about how we might trigger end of game!) 为了解决这个难题,我们将实现以下逻辑以完成游戏:(To fix this dilemma, we would implement the following logic to have a finish to the game play:)
-
计时器为0.00时,游戏应停止.(The game should stop when the timer is 0.00.)
-
当玩家在场景中收集所有硬币时,游戏应停止.(The game should stop when the player collects all of the coins on the scene.)
在游戏结束时,我们需要向用户显示提示,显示他们的得分,并且还使他们能够开始新游戏或结束游戏.(At the end of the game, we need to display a prompt to the user displaying their score, and also giving them the ability to start a new game or ending the game.) **注意:(NOTE:)**必须根据部署游戏的平台来定义应用程序的退出! Web应用程序上没有应用程序退出之类的东西!(Exit of an application has to be defined based on the platform the game is deployed on! There is no such thing as an Application Exit on a Web Application!) 以下代码清单显示了如何修改代码以处理案例(1)和案例(2)以触发游戏结束:(The following code listing shows how we would modify our code to handle case (1) and case (2) to trigger an end of game:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class playerInput : MonoBehaviour {
public Text lblScore; // text UI element for displaying score
public Text lblTimer; // text UI element for displaying timer
private int score; // internal score variable
public int SCORE
{
get{ return this.score; }
}
private float levelTime; // variable holing time to complete level
private float timeLeft; // variable for the actual timer count down
public bool END_GAME; // variable indicating end of game
public int numOfCoinsInLevel; // will be initialized at the Start of the game
public int numOfCoinsCollected; // will be incremented each time we collect a coin
// Use this for initialization
void Start () {
this.score = 0;
this.timer = 60.00f;
this.numOfCoinsCollected = 0;
this.END_GAME = false;
// check to make sure labels are defined before updating
if (this.lblScore != null)
this.lblScore.text = this.score.ToString();
if (this.lblTimer != null)
this.lblTimer.text = string.Format("{0:F2}", this.timer - Time.time);
// get number of coins in the scene at the start of the game
this.numOfCoinsInLevel = GameObject.FindGameObjectsWithTag ("coin").Length;
}
// Update is called once per frame
void Update () {
if (!this.END_GAME) {
// compute time left
this.timeLeft = this.timer - Time.time;
// update UI label for timer
if (this.lblTimer != null){
this.lblTimer.text = string.Format("{0:F2}", this.timeLeft);
}
// check to see if we need to end the game based on the timer
if(this.timeLeft<=0.00f || this.numOfCoinsInLevel<=this.numOfCoinsCollected){
this.END_GAME = true;
if (this.lblTimer != null){
this.lblTimer.text = string.Format("{0:F2}", 0.00f);
}
}
// code for the movement of player (CP) forward
if(Input.GetKey(KeyCode.UpArrow)){
this.transform.Translate(Vector3.forward * Time.deltaTime);
}
// code for the movement of player (CP) backward
if(Input.GetKey(KeyCode.DownArrow)){
this.transform.Translate(Vector3.back * Time.deltaTime);
}
// code for the movement of player (CP) left
if(Input.GetKey(KeyCode.LeftArrow)){
this.transform.Rotate(Vector3.up, -5);
}
// code for the movement of player (CP) right
if(Input.GetKey(KeyCode.RightArrow)){
this.transform.Rotate(Vector3.up, 5);
}
}else{
Debug.Log("GAME ENDED!!!");
}
}
// This event will be raised by object that have their Is Trigger attributed enabled.
// In our case, the coin GameObject has Is Trigger set to true on its collider.
void OnTriggerEnter(Collider c){
if(c.tag.Equals("coin")){
Coin coin = c.GetComponent<Coin>();
// increase score
this.score += coin.VALUE;
this.numOfCoinsCollected += 1;
// update score on the UI
if (this.lblScore != null)
this.lblScore.text = this.score.ToString();
// remove the Coin object from the scene
Destroy(c.gameObject);
}
}
}
查看新清单,您会注意到代码中有很多更改.没什么大的或复杂的,但是,现在我们的代码有了更多的内容.(Taking a look at the new listing, you will notice that there is a lot of changes in the code. Nothing major or complex, but nevertheless, we have more meat to our code now.)
我们还引入了更多变量来跟踪游戏中的统计数据.一个新变量(We also have introduced a few more variables to keep track of statistics in our game. A new variable,)剩下的时间(timeLeft),因为引入了计时器来处理时间到了何时终止游戏!布尔变量(, for the timer is introduced to handle when to terminate the game when the time is up! A Boolean variable)**结束游戏(END_GAME)**引入作为标志来确定游戏是否应该继续结束.两个变量(is introduced as a flag to determine if the game should continue of end. Two variables)**numOfCoinsInLevel(numOfCoinsInLevel)**和(and)**numOfCoinsCollected(numOfCoinsCollected)**确定如果玩家在时间到之前已经收集了关卡中的所有硬币,是否应该结束游戏.(to determine if game should be ended if the player has collected all of the coins in the level before the time is up.)
下一步是创建将在游戏结束时显示的UI.同样,这里没有什么幻想,但我们将尽力取悦.下图将显示"最终游戏"面板的外观:(The next step is create the UI that will be displayed at the end of the game. Again, nothing fancy here, but we will try to make something pleasing. The following figure will display the look of our End Game panel:)
图5:游戏画布显示结束(Figure 5-End of Game Canvas Display) 与往常一样,我们将需要更新脚本以处理新的增强功能.这是(As always, we will need to update our script to handle the new enhancements. Here is an updated listing of the)**playerInput.cs(playerInput.cs)**脚本:(script:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class playerInput : MonoBehaviour {
public Text lblScore; // text UI element for displaying score
public Text lblTimer; // text UI element for displaying timer
public Canvas endGameCanvas; // Canvas holding UI elements for End of Game
public Text lblEndOfGameScore;
public Text lblEndOfGameTime;
public Text lblEndOfGameCoinCont;
private int score; // internal score variable
public int SCORE
{
get{ return this.score; }
}
private float levelTime; // variable holing time to complete level
private float timeLeft; // variable for the actual timer count down
public bool END_GAME; // variable indicating end of game
public int numOfCoinsInLevel; // will be initialized at the Start of the game
public int numOfCoinsCollected; // will be incremented each time we collect a coin
// Use this for initialization
void Start () {
this.score = 0;
this.levelTime = Time.time + 30.00f;
this.numOfCoinsCollected = 0;
this.END_GAME = false;
this.endGameCanvas.gameObject.SetActive(false);
// check to make sure labels are defined before updating
if (this.lblScore != null)
this.lblScore.text = this.score.ToString();
if (this.lblTimer != null)
this.lblTimer.text = string.Format("{0:F2}", this.levelTime - Time.time);
// get number of coins in the scene at the start of the game
this.numOfCoinsInLevel = GameObject.FindGameObjectsWithTag ("coin").Length;
}
// Update is called once per frame
void Update () {
if (!this.END_GAME) {
// compute time left
this.timeLeft = this.levelTime - Time.time;
// update UI label for timer
if (this.lblTimer != null){
this.lblTimer.text = string.Format("{0:F2}", this.timeLeft);
}
// check to see if we need to end the game based on the timer
if(this.timeLeft<=0.00f || this.numOfCoinsInLevel<=this.numOfCoinsCollected){
this.END_GAME = true;
if (this.lblTimer != null && this.lblEndOfGameTime != null){
if(this.timeLeft>=0.00f){
this.lblTimer.text = string.Format("{0:F2}", this.timeLeft);
this.lblEndOfGameTime.text = string.Format("{0:F2}", this.timeLeft);
}else{
// this else block is written to ensure that if the timer is up, we always get 0.00
// and not positive or negative values, i.e. 0.01, or -0.01 and etc...
this.lblTimer.text = string.Format("{0:F2}", 0.00f);
this.lblEndOfGameTime.text = string.Format("{0:F2}", 0.00f);
}
}
if(this.lblEndOfGameScore != null && this.lblEndOfGameCoinCont != null){
this.lblEndOfGameScore.text = this.SCORE.ToString();
this.lblEndOfGameCoinCont.text = this.numOfCoinsCollected.ToString();
}
}
// code for the movement of player (CP) forward
if(Input.GetKey(KeyCode.UpArrow)){
this.transform.Translate(Vector3.forward * Time.deltaTime);
}
// code for the movement of player (CP) backward
if(Input.GetKey(KeyCode.DownArrow)){
this.transform.Translate(Vector3.back * Time.deltaTime);
}
// code for the movement of player (CP) left
if(Input.GetKey(KeyCode.LeftArrow)){
this.transform.Rotate(Vector3.up, -5);
}
// code for the movement of player (CP) right
if(Input.GetKey(KeyCode.RightArrow)){
this.transform.Rotate(Vector3.up, 5);
}
}else{
this.endGameCanvas.gameObject.SetActive(true);
}
}
// This event will be raised by object that have their Is Trigger attributed enabled.
// In our case, the coin GameObject has Is Trigger set to true on its collider.
void OnTriggerEnter(Collider c){
if(c.tag.Equals("coin")){
Coin coin = c.GetComponent<Coin>();
// increase score
this.score += coin.VALUE;
this.numOfCoinsCollected += 1;
// update score on the UI
if (this.lblScore != null)
this.lblScore.text = this.score.ToString();
// remove the Coin object from the scene
Destroy(c.gameObject);
}
}
public void butPlayAgain_Click(){
Start ();
}
}
兴趣点(Points of Interest)
如您所见,事情变得越来越复杂了!还有一些我们没有考虑的情况.假设出现以下情况,假设玩家在游戏期间收集了场景中的所有硬币,那么在游戏结束时,他们可以选择再次玩.但是这里有一个我们没有解决的问题!你能说出问题是什么吗?在继续阅读下一段之前请三思.(As you can see, things are getting pretty involved! Also there are several scenarios we are not taking into consideration. Assume the following scenario, let’s say the player collects all of the coins in the scene during their play time, at the end of the game, they get an option to play again. But there is a problem here which we have not handled! Can you tell what the issue is? Think a bit before you continue on reading the next paragraph.) 问题是我们在设计时就将硬币放到了场景中!因此,当我们在运行时收集硬币时,实际上会将它们从内存中删除!看到问题了吗?好吧,问题在于,我们目前无法在场景上重新创建这些硬币,因此当游戏再次开始时,它将立即停止,因为有零个硬币!我们将在第7部分中尝试解决此问题.(The issue is that we have placed our coins in the scene at design time! So when we collect the coins at runtime, we actually remove them from memory! Do you see the problem? Well, the problem is that there is no way for us to recreate these coins on the scene at the moment, so when the game starts again, it will immediately stop, because there are zero coins! We will try to solve this issue in Part 7.) **注意:(NOTE:)**注意,我没有深入了解制作UI的细节.第4部分介绍了该主题.(Notice I did not get into the details on making the UI. The topic was covered in Part 4.)
历史(History)
这是系列文章的第六篇,我将慢慢为Code Project社区做出贡献.(This is the sixth article of a series which I would slowly contribute to the Code Project community.)
-
Unity 3D –游戏编程–第6部分(Unity 3D – Game Programming – Part 6)
Unity 3D网络文章:(Unity 3D Networking Article(s):)
-
Unity 3D-网络游戏编程(Unity 3D - Network Game Programming) Unity 3D Leap Motion和Oculus Rift文章:(Unity 3D Leap Motion and Oculus Rift Article(s):)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# .NET Mobile iPhone Android Windows Dev designer 新闻 翻译