UNITY 3D –游戏编程–第4部分(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/unity-d-game-programming-part-3-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 30 分钟阅读 - 14784 个词 阅读量 0UNITY 3D –游戏编程–第4部分(译文)
原文地址:https://www.codeproject.com/Articles/879502/UNITY-D-Game-Programming-Part-3
原文作者:Vahe Karamian
译文由本站 robot-v1.0 翻译
前言
The fourth article in a series to discuss Unity 3D and how to get started with your own 3D projects.
该系列的第四篇文章讨论Unity 3D以及如何开始自己的3D项目.
介绍(Introduction)
在本系列的第四部分中,我们将研究如何使用Unity 3D中的新UI架构创建用户界面元素.在我们的代码库的基础上,我们将创建一个简单的界面来执行我们通过键盘输入进行编程的某些功能.(In part four of the series, we will look at creating user interface elements using the new UI architecture in Unity 3D. Building on our code base, we will create a simple interface to perform some of the functions that we have been programming through the keyboard input in) 第2部分(Part 2) 和(and) 第三部分(Part 3) 系列中的.如果您尚未这样做,请花一点时间阅读:(of the series. If you have not already done so, please take a moment and read:)
-
Unity 3D –游戏编程–第4部分(Unity 3D – Game Programming – Part 4)
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.) 在本系列的第4部分中,我们将着眼于创建一个简单的用户界面.我们将开发的用户界面将为我们提供一种向用户反馈的方式,并且还为用户提供了输入我们的游戏或仿真的另一种方法.(In Part 4 of the series, we will look at creating a simple user interface. The user interface that we will develop will provide us a means to feedback to the user, and also another method for the user to input to our game or simulation.)
游戏编程简介:使用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)
假定本文的读者通常熟悉编程概念.还假定读者具有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.)
Unity 3D中的用户界面设计(User Interface Design in Unity 3D)
如您所知,每个程序都由一些输入和一些输出组成.在本系列的第3部分中,我们研究了如何通过计算机键盘从用户那里获得输入.现在,我们将研究如何向用户显示反馈,以使他(她)对程序中发生的事情有更好的了解,并继续通过创建另一种方法供用户输入程序.(As you are aware of, every program is composed of some input and some output. In Part 3 of the series we looked at how to get input from the user through the computer keyboard. Now, we are going to look at how to display feedback to our user based so that he/she has a better idea of what is going on in the program, and also continue by creating another means for the user to input to the program.)
**注意:(NOTE:)**我们将要构建的用户界面仅适用于Unity 3D 4.6.1及更高版本.(The User Interface that we are going to build will only be applicable to Unity 3D version 4.6.1 and above.)
在Unity 3D的最新版本发布之前,游戏程序员和设计师必须花费大量时间才能正确开发游戏用户界面.他们必须通过编码和编程来完成大部分设计.在最新版本中,我们有一个更好的引擎来处理UI部分,因此将大大提高UI开发效率.(Prior to the latest release on Unity 3D, a game programmer and designer had to spend a significant amount of time for the proper development of their user interface for the game. And they had to do most of the design through coding and programming. With the latest release, we have a better engine to handle the UI portion and hence will significantly improve the efficiency of the UI development.)
假设您已按照本系列的所有部分进行操作,那么打开我们的Unity 3D项目.您将看到一个类似于以下场景的场景:(Assuming you have followed all of the parts in the series, let’s open our Unity 3D project. You will have a scene looking like the one below:)
图1:第3部分中的代码屏幕截图(Figure 1-Screenshot of Code From Part 3)
让我们继续创建一个(Let’s go ahead and create a)平视显示器(HUD)**(抬头显示)((Heads Up Display))**它将显示场景中每个基本体的位置和旋转.(that will display the position and rotation for each of the primitives that we have in the scene.)
如果您还记得以前的文章,我们有3个设计时原语(多维数据集)已使用设计器放置在场景中,如上图所示.我们有一个脚本,当我们按下键盘上的空格键时,它将在运行时创建另外三个基本体(多维数据集).(If you recall from the previous articles, we have three design time primitives (cubes) that have been placed in the scene using the designer, as shown in the figure above. And we have a script which will create three more additional primitives (cubes) at runtime when we press the Space Bar on the keyboard.)
要绘制UI元素,我们需要创建一个UI Canvas.这很重要,每个UI元素都必须是要在屏幕上绘制的Canvas的子级.(To draw the UI elements, we would need to create a UI Canvas. This is important, every single UI element needs to be a child of a Canvas to be drawn on the screen.)
要创建UI画布,请在Unity 3D的"层次结构"窗口中右键单击鼠标,然后将弹出一个上下文菜单:(To create a UI Canvas, Right-Click your mouse within the Hierarchy window in Unity 3D and you will get a context menu up:)
图2:在"层次结构"窗口中右键单击后的上下文菜单(Figure 2-Context Menu After Right-Click in Hierarchy Window) 请注意,在上下文菜单的UI菜单下,您可以使用的UI项.这些是:(Notice, under the UI Menu within the Context Menu, the UI Items that are available to you. These are:)
-
面板(Panel)
-
纽扣(Button)
-
文本(Text)
-
图片(Image)
-
原始图像(RawImage)
-
滑杆(Slider)
-
滚动条(Scrollbar)
-
切换(Toggle)
-
InputField(InputField)
-
帆布(Canvas)
-
事件系统(EventSystem)
如您所见,您限于可用的UI元素类型,但是尽管如此,您仍然拥有实现游戏或模拟所需功能所需的一切.有了一点创意,这些UI元素将大有帮助!(As you can see, you are limited to the types of UI elements available to you, but nevertheless, you have everything you need to implement the necessary functions for your game or simulation. With a little bit of creativity, these UI elements will go a long way!)
继续,然后从菜单中选择"画布"对象.这样做时,您会注意到已经在场景中自动放置了两个新的GameObject,(Go ahead and select the Canvas object from the menu. When you do so, you will notice that two new GameObjects have been automatically placed in your scene,)帆布(Canvas)和(and)事件系统(EventSystem):(:)
图3-注意场景中放置了两个新对象(Figure 3-Notice Two New Objects Got Placed in Your Scene)
我们将使用相同的方法添加UI元素.每次我们想要添加UI元素时,我们都将右键单击以获取上下文菜单,然后在UI菜单下选择适当的UI组件.(We will be adding our UI elements using the same method. Each time we want to add a UI element we will Right-Click to get the Context Menu and then select the proper UI component under the UI menu.)
假设我们要根据以下草图创建UI:(So let’s say we want to create our UI based on the following sketch:)
图4-我们的用户界面示意图(Figure 4-Sketch of Our User Interface)
创建用户界面-面板1(Creating the User Interface - Panel 1)
我们可以开始创建如图4所示的用户界面.首先开始做Panel1.在Hierarchy窗口中,选择(We can start creating our user interface as sketched in Figure 4. Let’s start by first doing Panel 1. Within the Hierarchy window, select the)帆布(Canvas)单击GameObject,然后单击鼠标右键以打开上下文菜单.选择UI-> Panel插入一个(GameObject and right-click to get the context menu up. Select UI->Panel to insert a)面板(Panel)场景中的GameObject.双击(GameObject in the scene. Double click the)面板(Panel)GameObject使其专注于"场景视图",如下图所示:(GameObject to have it focused on the Scene View as show in the following figure:)
图5-显示在画布上绘制的面板的屏幕截图(Figure 5-Screenshot Showing Panel Drawn on Canvas)
这里发生了很多事情.首先,请注意,当您双击"层次结构"窗口中列出的项目时,“场景视图"将集中在场景中的指定对象上.因此,顺便提一下,如果您想在更复杂的场景中专注于给定的对象,只需双击它即可.(There are a lot of things going on here. First, notice that when you double click an item listed in the Hierarchy window, the Scene View focuses on the specified object in the scene. So, just on a side note, if you want to focus on a given object in a more complex scene, just double click on it.)
其次,更重要的是,看一看Inspector窗口(在图5中标记为1).让我们花点时间在这里讨论一些重要的概念.(Second and more importantly, take a look at the Inspector Window, marked as number 1 in Figure 5. Let’s take a moment and discuss a few important concepts here.)
|
图6-面板的检查器窗口(Figure 6-Inspector Window for Panel) |您应该熟悉(You should be familiar with the)检查器窗口(Inspector Window)目前为止.该窗口列出了给定对象的所有附加组件,并且基于"对象类型”,它将列出不同的组件.(by now. This window lists all of the attached components to a given object, and based on the Object Type, it will list different components.) 查看图6,您会注意到我突出显示的三个区域:(Looking at Figure 6, you notice three areas that I have highlighted:)
- 矩形变换(Rect Transform)
- 图片(Image)
- 面板(Panel)
的(The)矩形变换(Rect Transform)组件是您应该熟悉的最重要的组件.它将用于您的定位和锚固(component is the most important one that you should become familiar with. It is going to be used for the positioning and anchoring of your)UI对象(UI Objects)关于彼此!(in respect to one another!)
我们将广泛使用Rect变换来放置和定位UI元素.稍后再详细介绍.(We will be using the Rect Transform extensively to place and position our UI elements. More on this later.)
Image组件将成为给定UI元素的背景纹理.假设UI元素支持这样的属性.开箱即用,每个UI元素都使用引擎设计的每个UI元素的默认纹理和变换.(The Image components is going to be the background texture for a given UI element. Given that the UI element supports such an attribute. Out of the box, each UI element uses the default textures and Transforms for each UI element as designed by the engine.)
最后,面板组件显示面板背景图像的外观.稍后还将对此进行详细说明!(Finally, the Panel component, show the look and feel of the panel’s background image. More on this later as well!)
我们继续使用变形工具来调整面板的位置和大小.我们希望将面板固定到(Let’s go ahead and use the transform tool to adjust the position and size of the panel. We would want to anchor our panel to the)左上角(TOP LEFT CORNER)屏幕的使用现有的锚设置,我们可以简单地使用欲望(of the screen. Using the pre-existing anchor settings, we can simply use the desires)锚点预设(Anchor Preset)如图7所示.(as shown in Figure 7.)
提出(To bring up the)锚点预设(Anchor Preset)在配置窗口中,单击图7中标记为1(一个)的区域.您将获得一个新窗口,在图7中标记为2(两个),列出所有预设.从现有的预设中,选择一个代表屏幕左上角的预设.(configuration window, click in the region marked as 1 (one) in Figure 7. You will get a new window, marked as 2 (two) in Figure 7, listing all of the presets. From the existing presets, select the one that represent the top left corner of the screen.)
图7-显示预配置锚(Figure 7-Display Pre-Configured Anchors)
当您更改锚设置时,您会注意到,(When you change the anchor settings, you will notice, that the)矩形变换(Rect Transform)属性也已更新,以反映新的锚定(properties have also been updated to reflect the new anchoring of the)面板(Panel)游戏对象.默认情况下,它会填充整个Canvas GameObject表面积.(GameObject. By defaults it fills the whole Canvas GameObject surface area.)
来吧(Go ahead and)宽度(width)和(and)高度(height)的属性(properties to the)矩形变换(Rect Transform)至(to)200 x 100(200 x 100)分别.您应该在视图中具有如下视图:(respectively. You should have a view like the following in your view:)
图8:面板锚定和尺寸设置后的外观(Figure 8-Panel Look After Anchoring and Size Settings)
现在,我们想将Panel GameObject移到靠近(Now, we would like to move the Panel GameObject close to the)**左上角(Top Left Corner)**通过定位.使用定位工具,可以将其移动到您希望作为设计师的区域.您也可以使用(through positioning. Using the positioning tool, you can move it to the region you prefer as a designer. You can also use the)矩形变换(Rect Transform)将特定的数字应用于(to apply specific numeric numbers for the)位置X(Pos X)和(and)位置Y(Pos Y)零件.在这种情况下,位置Z始终为0.(component. In this case Pos Z will always be 0.)
图9-定位到左上角后的面板(Figure 9-Panel after Positioning to Top Left Corner)
图9中需要注意几件事.首先,请注意在设计时的"场景视图"中,面板的实际位置似乎在右侧.这是因为我们正在从背面看画布对象.这意味着什么?(Several things to note in Figure 9. First, notice that in the Scene View, at design, time the actual location of the Panel seems to be on the right hand side. This is because we are looking at the Canvas Object from the back. What does that mean?)
好吧,看看红色,绿色和蓝色的三个彩色箭头.这些箭头表示3D环境中每个轴的正方向.如果您现在还没有弄清楚,则红色箭头表示X轴,并且箭头始终指向正极.绿色箭头表示Y轴,并且箭头始终指向正极.蓝色箭头表示Z轴,并且箭头始终指向正方向.(Well, take a look at the three colored arrows red, green and blue. These arrows represent the positive direction of each axis in the 3D environment. If you have not figured this out by now, the red arrow represents the X-Axis, and the arrow is always directed towards the positive. The green arrow represents the Y-Axis, and the arrow is always directed towards the positive. The blue arrow represents the Z-Axis, and the arrow is always directed towards the positive direction.)
在图9中,查看编号为2(两个)和3(三个)的区域.您会注意到(In Figure 9, look at the region numbered 2 (two) and 3 (three). You will notice that the)矩形变换(Rect Transform)已修改为(has been modified to have)**Pos X设置为110(Pos X set to 110)**和(and)位置Y设置为-60(Pos Y set to -60).这是从锚点(左上角)开始的位移.(. This is the displacement from the anchor point, which is the Top Left Corner.)
这里没有魔术,您只需要进行定位和缩放即可获得UI设计的正确感觉.(There is no magic here, you just need to play with the positioning and the scaling to get the right feel for your UI design.)
现在我们已经添加了面板,让我们继续并添加标签,这些标签将显示图元的位置和旋转.(Now that we have added our Panel, let’s go ahead and add the labels which will display the position and the rotation of our primitives.)
在"层次结构"窗口中,右键单击面板GameObject,然后选择UI-> Text.(In the Hierarchy Window, Right-Click the Panel GameObject and select UI->Text.)
图10-第一个文本UI元素(Figure 10-First Text UI Element)
就像我们的Panel UI元素一样,我们继续将Text UI元素的锚点更改为"左上角",然后使用(Just like our Panel UI element, let’s go ahead and change the anchoring of our Text UI element, to Top Left Corner, then using the)矩形变换(Rect Transform)或设计时定位工具进行调整并将其正确放置在面板的左上角.还将Text UI元素的名称更改为lblCube1Position.(or the design time positioning tool to adjust it and place it properly on the Top Left Corner of our Panel. Also change the name of the Text UI element to lblCube1Position.)
图11-配置后Cube1基本体标签的位置(Figure 11-Position of Cube1 Primitives Label after Configuration)
继续进行操作,再放置两个Text UI元素,并根据图4中的草图进行放置.如果您正确完成了所有操作,则将得到类似下图的内容:(Go ahead and place two more Text UI elements as we did and position them according to our sketch in Figure 4. If you have done everything correctly, you will have something like the following figure:)
图12-最终面板查找设计时基元(Figure 12-Final Panel Look for Design Time Primitives) 好的,现在我们有一个面板可以显示在设计时创建的图元的位置和旋转.(Ok, so now we have one of our panels designed to display the position and rotation of the primitives created at design time from) 第1部分(Part 1) .现在,我们需要编写一些代码来实际更新标签.我们需要更新以前的脚本来处理来自(. Now we need to write some code to actual update our labels. We would need to update our previous scripts that handled the primitive rotation from) 第2部分(Part 2) 我们的系列.(of our series.) 您还记得吗,我们为每个多维数据集基元创建了三个单独的脚本,并将旋转应用于图元中的基元(If you recall, we created three separate scripts for each cube primitive and applied the rotation to the primitive in the)更新()(Update())该脚本.现在,我们将需要更新这些脚本,以便能够为每个原语更新标签.让我们继续修改Cube1的脚本.(of that script. Now, we will need to update these scripts to be able to update our labels for each primitive. Let’s go ahead and modify the script for Cube1.) 我们将我们的cube1Rotate.cs脚本修改为以下列表:(We will modify our cube1Rotate.cs script to the following listing:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class cube1Rotate : MonoBehaviour {
// variable to store Text UI Element
public Text lblCube1Position;
private string position = "";
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
// Rotate our game object around it's y-axis
this.transform.Rotate (new Vector3 (0, 1, 0), 1);
if (this.lblCube1Position != null) {
position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.transform.localPosition.x,
this.transform.localPosition.y,
this.transform.localPosition.z,
this.transform.localEulerAngles.x,
this.transform.localEulerAngles.y,
this.transform.localEulerAngles.z);
this.lblCube1Position.text = position;
}
}
}
查看上面的清单时,您会注意到我们创建了一个类型为public的公共变量(When you review the listing above, you will notice that we have created a public variable of type)文本(Text).另请注意,我们必须导入(. Also notice that we had to import the)UnityEngine.UI(UnityEngine.UI)名称空间,以便能够在我们的代码中使用UI对象.(namespace to be able to use the UI Objects in our code.)
然后在我们的(Then in our)更新()(Update())函数,我们添加了几行代码来检查(function we have added a few lines of code to check to see if the)lblCube1Position(lblCube1Position)变量已初始化,如果是,则继续构建一个字符串,该字符串将表示给定对象的位置和旋转,最后,我们将新构造的字符串分配给对象的文本字段(variable is initialized, and if it is, then we go ahead and construct a string that will represent the position and the rotation of the given object, and finally we assign the newly constructed string to the text field of the)lblCube1Position(lblCube1Position)UI元素.(UI element.)
第一步是更新脚本,以便能够处理所需信息的更新和显示.第二步是确保在设计器中正确配置了我们新创建的脚本.(The first step was to update out script to be able to handle the updating and displaying of the information desired. The second step would be to make sure that our newly created script gets properly configured in the designer.)
图13-lblCube1Position文本变量的设计时间分配(Figure 13-Design Time Assignment of lblCube1Position Text Variable) 如图13所示,您需要将Text UI元素分配给(As shown in Figure 13, you will need to assign the Text UI element to the)文本(Text)在脚本中定义的变量.一种方法是,在具有cube1Rotate.cs的场景中选择GameObject,然后将lblCube1Position Text UI元素拖放到其中.(variable defined in our script. One way to do this, is to select the GameObject in the scene that has the cube1Rotate.cs and drag-n-drop the lblCube1Position Text UI element from the)层次窗口(Hierarchy Window)(1)进入脚本文件(2)和(3)中定义的Text变量,如((1) onto the Text variable defined in the script file (2) and (3) as shown in the)检查器窗口(Inspector Window).(.) 运行此程序更新时,您将看到顶部的Text UI元素现在将显示位置和旋转.(When you run this program update, you will see that the top Text UI element will now display the position and the rotation.) **注意:(NOTE:)**由于文本的长度,我不得不调整面板UI元素和文本UI元素.正如预期的那样,这将在整个UI设计中发生.您将需要调整(I had to adjust my Panel UI element and the Text UI element(s) due to the length of the text. This will happen throughout your UI design, as it is expected. You will need to adjust the)矩形变换(Rect Transform)因此要考虑到屏幕上显示的数据量.(accordingly to take into consideration the amount of data it is being displayed on the screen.) 我已经更新了UI元素,如下所示:(I have updated my UI elements as follows:)
-
Panel UI元素具有以下配置:(Panel UI element to have the following configuration:)PoSX =130; PosY =-40;宽度=250;高度=75(PosX=130; PosY=-40; Width=250; Height=75).(.)
-
lblCube1Position的文本UI:(Text UI for lblCube1Position:)PosX =125; PosY =-20;宽度=230;高度=20;字体大小=12(PosX=125; PosY=-20; Width=230; Height=20; Font Size=12).(.)
-
lblCube2Position的文本UI:(Text UI for lblCube2Position:)PosX =125; PosY =-40;宽度=230;高度=20;字体大小=12(PosX=125; PosY=-40; Width=230; Height=20; Font Size=12).(.)
-
lblCube3Position的文本UI:(Text UI for lblCube3Position:)PosX =125; PosY =-60;宽度=230;高度=20;字体大小=12(PosX=125; PosY=-60; Width=230; Height=20; Font Size=12).(.)
图14显示Cube1的标签(Figure 14-Display Showing Label for Cube1) 继续执行与对Cube1执行的概念相同的概念,并将其应用于Cube2和Cube3.您将需要首先更新脚本,然后在设计视图中,将适当的Text UI元素分配给支持脚本中Text Object的变量.(Go ahead and perform the same concept we performed for Cube1, and apply them to Cube2 and Cube3. You will need to update the scripts first, and then in the design view, assign the appropriate Text UI element to the variable supporting the Text Object in the script.) 更新了cube2Rotate.cs的清单:(Updated listing for cube2Rotate.cs:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class cube2Rotate : MonoBehaviour {
// variable to store Text UI Element
public Text lblCube1Position;
private string position = "";
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
// Rotate our game object around it's x-axis
this.transform.Rotate (new Vector3 (1, 0, 0), 1);
if (this.lblCube1Position != null) {
position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.transform.localPosition.x,
this.transform.localPosition.y,
this.transform.localPosition.z,
this.transform.localEulerAngles.x,
this.transform.localEulerAngles.y,
this.transform.localEulerAngles.z);
this.lblCube1Position.text = position;
}
}
}
更新了cube3Rotate.cs的清单:(Updated listing for cube3Rotate.cs:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class cube3Rotate : MonoBehaviour {
// variable to store Text UI Element
public Text lblCube1Position;
private string position = "";
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
// Rotate our game object around it's z-axis
this.transform.Rotate (new Vector3 (0, 0, 1), 1);
if (this.lblCube1Position != null) {
position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.transform.localPosition.x,
this.transform.localPosition.y,
this.transform.localPosition.z,
this.transform.localEulerAngles.x,
this.transform.localEulerAngles.y,
this.transform.localEulerAngles.z);
this.lblCube1Position.text = position;
}
}
}
图15-最终面板查找设计时间基元的位置和旋转(Figure 15-The Final Panel Look for Position and Rotation of Design Time Primitives) 如您所见,在屏幕上正确设计和放置UI确实需要时间.这篇文章中显示的内容还有很多,但是我相信对于任何有兴趣深入研究的人来说,这都是一个好的开始.另外,请不要忘记,如前所述,在早期版本的引擎中,您将必须执行我们通过脚本执行的所有操作!(As you can see, it does take time to design and position your UI properly on the screen. There is much more to it then it is shown in this article, but I believe this is a good start for anyone who has an interest to delve deeper. Also, don’t forget, that as mentioned earlier, in prior versions of the engine, you would have to do everything we just did through scripting!)
创建用户界面-面板2(Creating the User Interface - Panel 2)
让我们继续创建第二个面板,该面板将执行相同的操作,但要针对动态创建的基元.我在这里不再重复这些步骤,因为它几乎相同,但是位置会有所不同.(Let’s go ahead and create our second panel that will do the same thing, but for the dynamically created primitives. I will not repeat the steps here, because it is pretty much the same, but the position will be different.)
您的环境应类似于以下内容:(Your environment should look something like the following:)
图16配置了面板2的屏幕视图(Figure 16-Screen View with Panel 2 Configured) 我们还需要修改处理动态原语的脚本(We would also need to modify our script that handles the dynamic primitives)**createPrimitivesFromInput.cs(createPrimitivesFromInput.cs)**如下:(as follows:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class createPrimitivesFromInput : MonoBehaviour {
private GameObject cube1; // represents our Cube1'
private GameObject cube2; // represents our Cube2'
private GameObject cube3; // represents our Cube3'
private bool PRIMITIVES_CREATED;
public Text lblCube1Position;
public Text lblCube2Position;
public Text lblCube3Position;
private string cube1position = "";
private string cube2position = "";
private string cube3position = "";
// Use this for initialization
void Start () {
this.PRIMITIVES_CREATED = false;
// update position information for each primitive
if(this.lblCube1Position != null){
this.lblCube1Position.text = this.cube1position;
}
if(this.lblCube2Position != null){
this.lblCube2Position.text = this.cube2position;
}
if(this.lblCube3Position != null){
this.lblCube3Position.text = this.cube3position;
}
}
// Update is called once per frame
void Update () {
if (!this.PRIMITIVES_CREATED) {
if (Input.GetKey (KeyCode.Space)) {
this.CreateMyPrimitives();
}
}else{
// apply the y-axis transform to Cube1'
if(Input.GetKey(KeyCode.A)){
this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
}
// apply the x-axis transform to Cube2'
if(Input.GetKey(KeyCode.B)){
this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
}
// apply the z-axis transform to Cube3'
if(Input.GetKey(KeyCode.C)){
this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
}
// code for the movement of Cube1' forward
if(Input.GetKey(KeyCode.UpArrow)){
this.cube1.transform.Translate(Vector3.forward * Time.deltaTime);
}
// code for the movement of Cube1' backward
if(Input.GetKey(KeyCode.DownArrow)){
this.cube1.transform.Translate(Vector3.back * Time.deltaTime);
}
// code for the movement of Cube1' left
if(Input.GetKey(KeyCode.LeftArrow)){
this.cube1.transform.Translate(Vector3.left * Time.deltaTime);
}
// code for the movement of Cube1' right
if(Input.GetKey(KeyCode.RightArrow)){
this.cube1.transform.Translate(Vector3.right * Time.deltaTime);
}
// update position information for each primitive
if(this.lblCube1Position != null){
this.cube1position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.cube1.transform.localPosition.x,
this.cube1.transform.localPosition.y,
this.cube1.transform.localPosition.z,
this.cube1.transform.localEulerAngles.x,
this.cube1.transform.localEulerAngles.y,
this.cube1.transform.localEulerAngles.z);
this.lblCube1Position.text = this.cube1position;
}
if(this.lblCube2Position != null){
this.cube2position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.cube2.transform.localPosition.x,
this.cube2.transform.localPosition.y,
this.cube2.transform.localPosition.z,
this.cube2.transform.localEulerAngles.x,
this.cube2.transform.localEulerAngles.y,
this.cube2.transform.localEulerAngles.z);
this.lblCube2Position.text = this.cube2position;
}
if(this.lblCube3Position != null){
this.cube3position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.cube3.transform.localPosition.x,
this.cube3.transform.localPosition.y,
this.cube3.transform.localPosition.z,
this.cube3.transform.localEulerAngles.x,
this.cube3.transform.localEulerAngles.y,
this.cube3.transform.localEulerAngles.z);
this.lblCube3Position.text = this.cube3position;
}
}
}
// This function will be called when the Space Bar on the keyboard is pressed
void CreateMyPrimitives(){
if (!this.PRIMITIVES_CREATED) {
// initialize our Cube1 primitive and place it at location (0,2,0)
this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube1.transform.localPosition = new Vector3 (0, 2, 0);
// initialize our Cube2 primitive and place it at location (3,2,0)
this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube2.transform.localPosition = new Vector3 (3, 2, 0);
// initialize our Cube3 primitive and place it at location (-3,2,0)
this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);
this.PRIMITIVES_CREATED = true;
}
}
}
更新脚本并在设计器中将适当的Text UI元素分配给适当的变量并运行程序后,您将看到以下内容:(After you update the script and in the designer assign the proper Text UI elements to the appropriate variables and run the program, you will see the following:)
图17-运行带有新更新的程序(Figure 17-Running Program with New Update)
如果您还记得本系列的第3部分,那么我们实现了从程序接收输入的功能.生成动态图元的输入是键盘上的空格键.当您按下空格键时,将显示以下屏幕:(If you recall from Part 3 of the series, we implemented to receive an input from the program. The input to generate the dynamic primitives was the Space Bar on the keyboard. When you press the Space Bar, you will get the following screen:)
图18-创建动态基元时(Figure 18-When Dynamic Primitives Are Created)
请注意,新创建的基元没有旋转,这是因为我们根据第3部分中的某些键盘输入使它们旋转.我们分配了A-Key来旋转Cube1',B-Key来旋转Cube2’和C-旋转Cube3’的键.这样做时,您将获得如下更新:(Notice that the newly created primitives are not rotating, and that is because we made them rotate based on some keyboard input in Part 3. We assigned the A-Key to rotate Cube1’, the B-Key to rotate Cube2’ and the C-Key to rotate Cube3’. When you do so, you will get the updates as follows:)
图19-显示所有位置和旋转信息(Figure 19-Displaying All Position and Rotation Information)
创建用户界面-创建按钮和事件处理(Creating the User Interface - Creating a Button and Event Handling)
到目前为止,我们已经研究了如何放置(So far, we have looked at how to place)面板(Panels)和(and)文本(Text)(标签)场景中的UI元素.让我们继续,现在看看如何介绍((Label) UI elements on the scene. Let’s go ahead and now see how we can introduce)纽扣(Buttons).一种(. A)纽扣(Button)通常用于用户单击,并且在单击后,程序中会引发某些特定事件或操作.(in general is used for the user to click on and after the click, some particular event or action gets raised in your program.)
这里的概念几乎相同. Button UI元素的放置,定位和缩放将与到目前为止我们讨论的Panel和Text UI元素完全相同.(The concept is pretty much the same here. The placement, positioning and scaling of the Button UI element is going to be exactly the same as the Panel and Text UI elements we have discussed so far.)
为了让我们放置一个按钮,我们将选择(In order for us to place a Button, we would select the)帆布(Canvas)我们的GameObject(GameObject in our)层次窗口(Hierarchy Window),然后单击鼠标右键以打开上下文菜单.从那里选择UI-> Button以将Button UI元素放置到场景中:(, and Right-Click to get the context menu up. From there select UI->Button to place a Button UI element into the scene:)
图20-在场景中创建的按钮(Figure 20-Button Created in Scene)
请注意,在图20中,(Notice in Figure 20, that the)纽扣(Button)对象本身有一个孩子(object itself has a child)文本(Text)目的.那就是按钮的标签!另请注意,(object. That is the label for the button! Also notice that the)纽扣(Button)对象对UI元素在场景上的锚定和定位具有相似的属性.让我们继续修改我们的锚定和位置(object has similar properties for the anchoring and positioning of the UI element on the scene. Let’s go ahead and modify the anchoring and positioning of our)纽扣(Button)根据图4.(based on Figure 4.)
的(The)纽扣(Button)将固定在屏幕的右上角:(will be anchored to the Right Top Corner of our screen:)
图21-按钮的最终位置(Figure 21-Final Placement of Our Button)
|
图22-按钮事件属性(Figure 22-Button Event Properties)
|看着(Looking at the)检查器窗口(Inspector Window),选择(, once you select the)纽扣(Button)场景中的UI元素.您会注意到按钮对象特有的几个属性.(UI element in the scene. You will notice several properties special to the Button Object.)
**注意:(NOTE:)我已经折叠了我们现在不打算讨论的,您已经熟悉的组件,即(I have collapsed the components which we are not going to discuss at this time, and which you are already familiar with, namely the)矩形变换(Rect Transform),以便我们有足够的屏幕空间来显示(, so that we have enough screen real estate to display the)按钮(脚本)(Button (script))零件.(component.)
在Unity 3D中,您将需要创建每个函数来处理系统中的特定事件.如果您习惯于在Windows或Web环境中双击UI对象,并让它自动为您创建具有适当参数的函数,那么这首先会有些不舒服.(In Unity 3D, you will need to create each function that will handle a particular event in the system. This at first is a little uncomfortable if you are used to double-clicking your UI object in a Windows or Web environment and have it automatically create a function with the appropriate parameters for you.)
查看图22,您会注意到(Looking at Figure 22, you notice the)在Click()上(On Click())已定义为占位符的事件,它尚未与任何内容关联!您将需要将其与功能关联!为此,您需要点击((event that is defined already as a placeholder, it is not associated with anything yet! You will need to associate it with a function! To do so, you will need to click on the ()+(+))图标(由图中的(1)表示).这样做时,您将获得以下信息:() icon indicated by a (1) in the Figure. When you do so, you will get the following:)
图22-On Click()事件已创建但未分配(Figure 22-On Click() Event Created, but Not Assigned)
请注意,没有任何内容分配给(Notice, there is nothing assigned to the)OnClick()(OnClick())占位符.这是我们分配GameObject的地方,负责处理(placeholder. This is where we would assign our GameObject that will be responsible handling the)OnClick(OnClick)我们的事件(event of our)纽扣(Button)在现场.(in the scene.) 我们将使用我们的(We will use our)**createPrimitiveFromInput.cs(createPrimitiveFromInput.cs)**脚本来处理我们的按钮单击事件.因此,我们继续将源代码修改为以下内容:(script to handle our button click event. So let’s go ahead and modify the source code to the following:)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class createPrimitivesFromInput : MonoBehaviour {
private GameObject cube1; // represents our Cube1'
private GameObject cube2; // represents our Cube2'
private GameObject cube3; // represents our Cube3'
private bool PRIMITIVES_CREATED;
public Text lblCube1Position;
public Text lblCube2Position;
public Text lblCube3Position;
private string cube1position = "";
private string cube2position = "";
private string cube3position = "";
// Use this for initialization
void Start () {
this.PRIMITIVES_CREATED = false;
// update position information for each primitive
if(this.lblCube1Position != null){
this.lblCube1Position.text = this.cube1position;
}
if(this.lblCube2Position != null){
this.lblCube2Position.text = this.cube2position;
}
if(this.lblCube3Position != null){
this.lblCube3Position.text = this.cube3position;
}
}
// Update is called once per frame
void Update () {
if (!this.PRIMITIVES_CREATED) {
if (Input.GetKey (KeyCode.Space)) {
this.CreateMyPrimitives();
}
}else{
// apply the y-axis transform to Cube1'
if(Input.GetKey(KeyCode.A)){
this.cube1.transform.Rotate(new Vector3(0,1,0), 1);
}
// apply the x-axis transform to Cube2'
if(Input.GetKey(KeyCode.B)){
this.cube2.transform.Rotate(new Vector3(1,0,0), 1);
}
// apply the z-axis transform to Cube3'
if(Input.GetKey(KeyCode.C)){
this.cube3.transform.Rotate(new Vector3(0,0,1), 1);
}
// code for the movement of Cube1' forward
if(Input.GetKey(KeyCode.UpArrow)){
this.cube1.transform.Translate(Vector3.forward * Time.deltaTime);
}
// code for the movement of Cube1' backward
if(Input.GetKey(KeyCode.DownArrow)){
this.cube1.transform.Translate(Vector3.back * Time.deltaTime);
}
// code for the movement of Cube1' left
if(Input.GetKey(KeyCode.LeftArrow)){
this.cube1.transform.Translate(Vector3.left * Time.deltaTime);
}
// code for the movement of Cube1' right
if(Input.GetKey(KeyCode.RightArrow)){
this.cube1.transform.Translate(Vector3.right * Time.deltaTime);
}
// update position information for each primitive
if(this.lblCube1Position != null){
this.cube1position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.cube1.transform.localPosition.x,
this.cube1.transform.localPosition.y,
this.cube1.transform.localPosition.z,
this.cube1.transform.localEulerAngles.x,
this.cube1.transform.localEulerAngles.y,
this.cube1.transform.localEulerAngles.z);
this.lblCube1Position.text = this.cube1position;
}
if(this.lblCube2Position != null){
this.cube2position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.cube2.transform.localPosition.x,
this.cube2.transform.localPosition.y,
this.cube2.transform.localPosition.z,
this.cube2.transform.localEulerAngles.x,
this.cube2.transform.localEulerAngles.y,
this.cube2.transform.localEulerAngles.z);
this.lblCube2Position.text = this.cube2position;
}
if(this.lblCube3Position != null){
this.cube3position = string.Format("P:<{0:F2},{1:F2},{2:F2}>; R:<{3:F2},{4:F2},{5:F2}>",
this.cube3.transform.localPosition.x,
this.cube3.transform.localPosition.y,
this.cube3.transform.localPosition.z,
this.cube3.transform.localEulerAngles.x,
this.cube3.transform.localEulerAngles.y,
this.cube3.transform.localEulerAngles.z);
this.lblCube3Position.text = this.cube3position;
}
}
}
// This function will be called when the Space Bar on the keyboard is pressed
public void CreateMyPrimitives(){
if (!this.PRIMITIVES_CREATED) {
// initialize our Cube1 primitive and place it at location (0,2,0)
this.cube1 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube1.transform.localPosition = new Vector3 (0, 2, 0);
// initialize our Cube2 primitive and place it at location (3,2,0)
this.cube2 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube2.transform.localPosition = new Vector3 (3, 2, 0);
// initialize our Cube3 primitive and place it at location (-3,2,0)
this.cube3 = GameObject.CreatePrimitive (PrimitiveType.Cube);
this.cube3.transform.localPosition = new Vector3 (-3, 2, 0);
this.PRIMITIVES_CREATED = true;
}
}
}
在这种情况下,我们要做的就是修改我们的(All we have to do in this case it to modify our)void CreateMyPrimitives()(void CreateMyPrimitives())功能使其成为公共功能,例如(function to make it a public function, like)公共无效CreateMyPrimitives()(public void CreateMyPrimitives()).(.)
**注意:(NOTE:)所有事件函数都必须无效且公开!(All event functions have to be void and public!)
这将是第一步.创建脚本来为我们处理事件.第二步是将分配脚本的对象分配给图23中列出的Button元素的事件处理程序.(This would be step one. Creating the script to handle the event for us. Step two will be to assign the object that the script is assigned to, to the event handler of the Button element listed in Figure 23.)
就我们而言,(In our case, the)**createPrimitivesFromInput.cs(createPrimitivesFromInput.cs)**附加到我们的(is attached to our)主相机(Main Camera)游戏对象.所以你会选择(GameObject. So you would select the)纽扣(Button)GameObject调出(GameObject to bring up the)检查器窗口(Inspector Window),然后将其拖放(, and then you will drag and drop the)主相机(Main Camera)GameObject进入(GameObject into the)OnClick()(OnClick())占位符.结果如下:(placeholder. The result would be the following:)
图24-分配给OnClick()按钮事件的主摄像机对象(Figure 24-Main Camera Object Assigned to OnClick() Button Event)
下一步将是从图24中箭头所指的下拉列表中获取函数.您将获得很多选择.我们对我们在Class中定义的功能感兴趣.因此,选择我们的类,然后从类中选择代表将处理事件的函数的函数.(The next step would be to get the function from the Drop-Down list pointed by the arrow in Figure 24. You will get a bunch of option. We are interested in the function we have defined in our Class. So select our Class and from within the Class select the function that represents our function that will handle the event.)
图25-显示按钮事件的类和功能的选择(Figure 25-Displays Selection of Class and Function for Button Event) 现在,您已经在Unity 3D中创建了您的第一个Interactive UI!恭喜你!现在运行程序时,可以使用空格键或我们刚刚在屏幕上创建的按钮,使用键盘实例化动态图元!(You have now created your first Interactive UI in Unity 3D! Congratulations! When you run the program now, you can instantiate the dynamic primitives either with your keyboard using the Space Bar, or the Button we just created on the screen!)
兴趣点(Points of Interest)
用户界面的设计和开发本身就是一个大主题,需要花费一些时间来掌握.在本文中,我们看到了一些非常基础的知识,可帮助您入门Unity 3D.这样做的目的是向您介绍这些概念,并让您自己走自己的路,并自行改进.(User interface design and development in itself is a large topic and one that will take time to master. In this article we saw some of the very basics to get you started in Unity 3D. The idea is to introduce you to the concepts and for you to take your own path and improve upon it on your own.)
历史(History)
这是系列文章的第四篇,我将慢慢为Code Project社区做出贡献.(This is the fourth article of a series which I would slowly contribute to the Code Project community.)
-
Unity 3D –游戏编程–第4部分(Unity 3D – Game Programming – Part 4)
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 Windows VS2010 Visual-Studio Dev Design Architect 新闻 翻译