UDN
Search public documentation:

UnrealScriptVariablesCH
English Translation
日本語訳
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 主页 > 虚幻脚本 >UnrealScript语言参考指南 > UnrealScript变量

UnrealScript变量


概述


类的属性称为 变量 。变量基本是数据的标识符或名称,在游戏过程中可以分配及修改变量的值。玩家的生命值、武器的弹药量、游戏得分 - 这些值都存放在一个类或另一个类的变量中,修改及访问这些变量或其他变量的值构成了游戏中游戏性的主要部分。

变量作用范围


在UnrealScript中可以声明两种类型的变量,这两种变量由于其作用范围不同而区分开来。变量的作用范围决定了变量的生命周期及变量的可用范围。

这两种类型的变量是:

  • Instance Variables(实例变量) - 这些变量应用于整个对象(类或结构体),并且在它们所属对象的整个生命周期内都可用。实例变量在创建对象时创建,在销毁对象时被销毁。这些变量可以在属于该对象的任何非静态函数中使用,或通过到该变量所属的的对象的引用可以从其他对象中访问该变量。
  • Local Variables(局部变量) - 这些变量是属于函数的“局部”变量,它们属于一个特定的函数。仅当执行函数时这些变量有效。当函数开始执行时创建这些局部变量,当函数执行结束时销毁这些变量。不能从其它函数或其他对象中使用或访问它们。

变量声明


变量声明将创建一个新的变量以便在某个类、结构体或函数中进行应用。变量声明由 varlocal 关键字及后面跟随的可选修饰符、要声明的变量的类型及变量名称构成。

var Type Name;
...
local Type Name;

可以在UnrealScript中的两个地方进行变量声明。实例变量声明紧跟在类声明(或在结构体生命中)的后面,并在任何函数或状态声明之前。局部变量声明位于函数体内,紧跟在函数声明的后面,位于函数中任何其他代码之前。实例变量使用关键字 var 进行定义。局部变量使用关键字 local 进行定义。

这里是在UnrealScript中的一些实例变量声明的例子:

class MyClass extends Actor;


// All istance variables must be declared before
// any functions or states are declared
var int A;			// Declare an integer variable named "A".
var byte Table[64];		// Declare a static array of 64 bytes named "Table".
var string PlayerName;		// Declare a string variable named "PlayerName".
var actor Other;		// Declare a variable which can be assigned a reference to an Actor instance.
var() float MaxTargetDist;	// Declare a float variable named "MaxTargetDist" and allow its value to be modified from an UnrealEd property window.

struct RangeVector
{
	var Vector Min;		// Declare a vector variable named "Min" within the struct.
	var Vector Max;		// Declare a vector variable named "Max" within the struct.
};

var RangeVector Bounds;		// Declare a RangeVector variable named "Bounds".

function foo
{
	...
}

var int B;			// This will cause an error

以下提供了局部变量声明的示例:

function int Foo()
{
	// All local variables must be declared before
	// any other code in the function body
	local int Count;
	local float Seconds;

	Count = 1;

	// Declaring a local variable here would cause an error
	local float Minutes;

	return Count;
}

变量修饰符

变量也可以包含其它的额外修饰符来对其进一步的描述,比如 const 。事实上,将会有很多你在一般的编程语言中没有见过的修饰符,这主要是因为我们想使UnrealScript支持许多游戏-和特定环境中-的专用概念:

config
这个变量是可以配置的。当前的值将被保存到一个ini文件中并在创建时加载。 这个变量不能在默认属性中赋值。 意味着它是常量。
globalconfig
和config的使用基本相同,除了不可以在子类中重写使用它所定义的变量。 这个变量不能在默认属性中赋值。 意味着它是常量。
localized
这个变量的值将会定义一个本地化变量。主要用于字符串。意味着它是常量。在本地化参考指南Unreal 字符串获得关于此的更多信息。
const
把变量的内容当成一个常量。在UnrealScript,你可以读取常量的值,但是你不能对其写入值。"Const"仅用于引擎来负责更新的变量及不能从UnrealScript中安全地进行更新的变量,比如一个物体的位置(仅能通过调用MoveActor函数来进行设置)。
private
这个变量是私有的,仅能通过该类的脚本来进行访问;其它的类(包括子类)不能访问该变量。
protected
这个变量仅能由此变量的类及其子类进行访问,其它类不能访问。
privatewrite
在声明该变量的类之外,该变量是常量型 const
protectedwrite
在声明该变量的类及其子类之外,该变量是常量型 const
repnotify
当通过复制接收到这个属性的值时,应该通知Actors(通过 ReplicatedEvent 函数)。
deprecated
意味着这个变量在不久的将来将会被删除,并且将不能在编辑器中访问。 Deprecated属性可以被加载,但不能被保存。
instanced
仅用于对象属性。 当创建了一个这个类的实例,将会默认地为这个变量赋予一个这个对象的唯一拷贝。 用于在类的默认属性中定义的实例化子对象。
databinding
这个属性可以通过数据库系统进行操作。
editoronly
属性值仅在运行UnrealEd或者一个命令开关时被加载。 在游戏中,这个属性值将被丢弃。
notforconsole
这个属性值将仅在运行PC时加载。 在游戏控制台中,该属性值被丢弃。

editconst
编辑器。这个变量可以在UnrealEd中看到,但不能被编辑。一个editconst变量并 暗示着它是"const"变量。
editfixedsize
编辑器。仅用于动态数组。这将防止用户通过UnrealEd属性窗口来改变数组的长度。
editinline
编辑器。允许用户编辑在UnrealEd属性窗口中编辑这个变量所引用的物体属性。(仅用于对象引用,包括数组对象的引用)。
editinlineuse
编辑器。 除了执行 editinline 的相关行为外,在编辑器中这个对象引用的旁边添加一个"Use"按钮。
noclear
编辑器。防止从编辑器中将该对象引用设置为None。
interp
编辑器。意味着这个值可以受到Matinee中的浮点或向量属性轨迹的驱动从而随时间改变。

input
高级。使得在Unreal的输入系统中是可以访问的该变量,从而使输入(比如按钮的押下和操作杆的运动)能够和变量直接地进行映射。仅和变量类型"byte"和"float"相关。

transient
高级。说明这个变量是临时使用的,且不是对象永久状态的一部分。Transient变量不会被保存到磁盘。当加载一个对象时,Transient变量被初始化为类的默认值。
duplicatetransient
高级。意味着当创建对象的一个二进制副本时,变量的值将被重置为类的默认值(通过StaticDuplicateObject).
noimport
高级。 意味着当导入T3D文本时,将跳过这个变量。 换句话说,当导入或者 复制/粘帖 对象时,这个变量的值将不会被传递到新的对象实例中。
native
高级。声明了这个变量通过C++代码进行加载和保存,而不是通过UnrealScript。
export
高级。仅对对象属性(或对象数组)有用。 意味着当一个对象被复制(复制/粘帖)或导出到T3D中而不是仅仅输出对象引用本身时,赋予给这个属性的对象应该作为一个子对象块整体地导出。
noexport
高级。仅用于native类。 这个变量不能包含在自动生成的类声明中。
nontransactional
高级。意味着这个变量值的改变将不会被包含到编辑器的 取消/重复 历史中。
pointer{type}
高级。 这个变量是一个指向 type(数据类型) 的指针 ( type(数据类型) 是随意的)。注意语法是: pointer varname(指针变量名){type(数据类型)}
init
高级。 这个属性将被作为FString或TArray而不是一个FStringNoInit 或TArrayNoInit导出到头文件中。 仅适用于在native类中声明的字符串和动态数组。 'Init'属性不能被赋予默认值,因为当创建对象时,默认值将会被清除。(请查看 Unreal 字符串Native 字符串)
repretry
高级;仅用于结构体属性。如果没能完全成功发送该属性(比如,网络上没有获得要进行序列化的对象应用)则重新复制它。对于简单的引用来说这个处理是默认的,但是对于结构体来说,由于带宽消耗通常我们不会将其作为默认修饰符,所以如果没有指定这个标志将会禁用该处理。
allowabstract
高进;仅用于对象引用。允许在编辑器中将抽象类赋予该变量。

out
这个修饰符仅对函数参数有效。 请查看函数参数修饰符页面来获取详细信息。
coerce
这个修饰符仅对函数参数有效。 请查看函数参数修饰符页面来获取详细信息。
optional
这个修饰符仅对函数参数有效。 请查看函数参数修饰符页面来获取详细信息。

skip
这个修饰符仅对运算符函数参数有效。 仅用于逻辑运算符比如&& 和 ||。如果可以通过第一个参数决定逻辑操作的结果,那么则告诉编译器插入一小段代码到程序流中以便跳过(不计算)第二个参数。

这保证了表达树中C语言风格的行为,比如:
   if( ++a==10 && ++b==10 )
   
这里,如果第一个表达式失败则跳过++b计算。

元数据

变量也可以通过在每个变量上指定元数据的形式来具有额外信息,以供引擎或编辑器使用,从而提供扩展功能。可以使用元数据指定一个显示名称、工具提示信息、其他东西之间的最小值和最大值。

要想将元数据链接到变量,您可以将它添加到变量声明中,它位于在变量名称的后面且在结束声明的分号的前面。元数据被指定为一系列成对的 Tag(标签)=Value(值) ,位于尖括号内由竖线 (|)分隔< >。

比如:

var float MyVar<DisplayName=My Float Variable|Tooltip=This is a float variable with additional metadata specified|UIMin=0.0|UIMax=10.0|ClampMin=0.0|ClampMax=5.0>;

请参照 UnrealScript元数据获得关于在UnrealScript中将元数据和变量结合使用的完整细节。

默认属性

在UnrealScript中,当声明变量时不会指定变量的默认值,这和其他编程语言中可以声明默认值不同。另外,在UnrealScript中创建的类没有用于设置默认值的“构造”函数的概念。反之,UnrealScript使用在类定义的脚本结尾处添加的 defaultproperties 块来指定在该类中声明的实例变量的默认值。该默认属性块中不允许执行代码,并且它遵循的某些规则和UnrealScript中其他地方使用的语法略有不同。

比如:

defaultproperties
{
   IntVar=3
   FloatVar=2.5
   StringVar="This is a string"
   ArrayVar(0)=2
   ArrayVar(1)=4
   ArrayVar(2)=7
   ArrayVar(3)=1
}

请参照UrnealScript默认属性页面获得关于使用UnrealScript指定变量默认值的完整细节,包括各种数据类型所使用的语法。

变量类型


UnrealScript包含了多个可以在声明变量时使用的内置数据类型。变量类型决定了它可以存放的数据的类型。某些类型非常简单,而有些类型却很难理解及应用。

基本数据类型

这里是UnrealScript中支持的通常可以在其他语言中找到的基本数据类型的列表:

byte(字节型)
范围是 0255 的一个字节值。
int(整型)
32位的整型值
bool(布尔型)
布尔值: truefalse
float(浮点型)
32位的浮点数。
string(字符串型)
一个字符串。(请参照虚幻字符串)。

constant(常量)
不能修改的变量。
enumeration(枚举型)
一个能够代表多个预先设定的整数值中其中一个值的变量。比如,在Actor脚本中定义的枚举类型ELightType描述了一个动态光源,它可以具有像 LT_None=、 =LT_Pulse=、 =LT_Strobe 等值。

集合数据类型

array<Type>(数组类型)
一个 Type 类型的数组。
struct
和C中的结构体类似,UnrealScript的structs可以让您创建包含子变量的新的变量类型。比如,两个常用的Unreal structs是由X坐标、Y坐标及Z坐标组成的 vector(向量) ;及由倾斜度、偏转度、旋转度组成的 rotator 。请参照 Structs(结构体)部分获得更多信息。

Unreal类型

Name
在Unreal中一个东西的名称(比如函数名、状态名、类名等)。 Names(名称)会作为一个索引存储到全局名称表中。Names(名称)和简单的字符串相对应,最多可以包含64个字符。Names(名称)不像字符串那样一旦创建不能改变(请查看Unreal 字符串获得更多的信息)。
对象和Actor引用
指向世界中另一个object 或 actor的变量。比如,Pawn类有一个 Enemy actor 引用,那么它指定了玩家应该攻击的物体。Object 及actor引用是非常强大的工具,因为它们使您可以访问另一个actor的变量及函数。比如,在Pawn的脚本中,你可以用 Enemy.TakeDamage(123) 来调用您的敌人的 TakeDamage 函数—从而导致敌人受到伤害。Object 引用也可能包含着一个特殊值 None= ,它和C 语言中的 NULL 指针是等同的: 它的意思是这个变量不能指向任何物体。
Delegate
保存着到一个Unrealscript函数的引用。

可编辑性


在UnrealScript中,你可以使一个实例变量变得可编辑,以便用户可以在UnrealEd中编辑变量的值。这个机制负责了UnrealEd的"Actor Properties(Actor属性)"对话框的全部内容: 您在那里所看到的全部内容仅是UnrealScript中的一个声明为可以编辑的变量。

声明一个可以编辑的变量的语法如下所示:

var() int MyInteger; // Declare an editable integer in the default
                     // category.

var(MyCategory) bool MyBool; // Declare an editable integer in
                             // "MyCategory".

您也可以声明一个变量为 editconst ,这意味着这个变量将可以在UnrealEd中看见但 可以编辑。注意这仅仅是为了防止变量在编辑器中被改变而不是在脚本中。如果您想使一个变量为真正的 const 但是仍然可以在编辑器中可见,您必须声明它为 const editconst

// MyBool is visible but not editable in UnrealEd
var(MyCategory) editconst bool MyBool;

// MyBool is visible but not editable in UnrealEd and
// not changeable in script
var(MyCategory) const editconst bool MyBool;

// MyBool is visible and can be set in UnrealEd but
// not changeable in script
var(MyCategory) const bool MyBool;

数组


数组使用以下语法声明:

var int MyArray[20]; // Declares an array of 20 ints.

UnrealScript仅支持一维数组,但你可以通过自己来设置 行/列 的数学处理来模拟多维数组。要获得关于动态数组的信息,请查看以下部分高级的语言功能

动态数组

先前我们所讲的数组是指静态数组。它意味着数组的大小(数组中有多少个元素)是在编译时设置的并且是不能改变的。动态数组和静态数组都有以下共同的特征:

  • 不变的搜索时间 – 时间代码在访问任何数组中给定的元素所花费的时间是相同的,无论在一个数组中有多少个元素。
  • 没有限制的元素类型 – 您可以创建任何类型的数组 - ints, vectors, Actors等(booleans除外,它仅对动态数组有效。)
  • 访问方式 – 您可以使用数组中的索引来访问任何元素,反过来说,尝试访问一个在数组范围之外的一个索引的元素将会抛出一个访问无效的警告信息。

为了适应数组元素变化的需要,动态数组提供了一种使静态数组具有在运行时改变元素数量的功能的方法。如果想使用动态数组,我们需要知道几件事情。

首先是变量的声明。声明一个动态数组和声明其它的unrealscript变量是非常相似的(也就是var/local 类型 变量名 )。 对于动态数组,类型可以使用关键字 array 来指定,后面跟着由尖括号括起的数组类型。 如果数组类型也包含尖括号(比如 class<Actor> ),你必须在类型的结束括号和数组的结束括号之间加入空格,否则编译器会把这两个结束括号作为 >> 操作符来处理。比如:
声明一个叫IntList的动态整型数组:

var array<int> IntList;

声明一个类型为 class<PlayerController> 、名称为Players的动态数组:

var array<class<PlayerController> > Players;

当脚本开始运行时,IntList将从0元素开始。动态数组所支持的方法允许我们向数组中添加元素、取出元素及任意地增加或降低数组的长度。调用这些方法的语法是(使用我们的IntList为例子): IntList.MethodName() 。以下是动态数组提供的方法:

  • Add(int Count): 通过使用 Count 来扩展数组的长度,和FArray::AddZeroed()一样。
  • Insert(int Index, int Count): Index_是插入元素的索引位置, _Count 是插入的元素数量。任何在那个位置存在的元素将会被上移,将会创建新的元素并把它们插入到指定的位置。在索引为3的位置插入5个元素将会使数组中从索引3开始的所有元素都会被上移5位。现在放在索引3出的元素将会被放置到索引8,元素4将是元素9等等。* Remove(int Index, int Count):_Index_ 是指从何处开始移除元素的索引, Count 是要移除的元素的数量。 新增加的元素都被初始化为默认值(除了structs包含structdefaultproperties外,其它所有元素将被初始化为 0/空)。
  • Remove(int Index, int Count): 这里 Index 是从其开始删除元素的数组索引, Count 是要删除的元素的数量。
 这允许我们从数组中任何有效的索引开始来移除数组中的一组元素。注意任何高于将被删除的范围的索引将会改变它们的索引值,如果您存储索引值到一个动态数组中时请记住这一点。
  • AddItem(Item): 在数组的末尾增加一个元素 Item ,从而是数组的长度加1。
  • RemoveItem(Item): 使用线性搜索来删除任何元素实例 Item
  • InsertItem(int Index, Item): 将元素 Item 插入到数组中的索引 Index 处,从而是数组的长度加1。
  • Find(...) - 查找一个元素在数组中的索引。有两个Find函数版本: 标准的查找函数是匹配所有的元素值,另一个专用版本的查找函数是基于struct的一个单独属性值来匹配一个struct。
    • Find(Value): Value 是要搜索的值。 返回在数组中第一个匹配指定值的元素的索引,如果没有找到返回-1。 Value 可以是任何有效的表达式。
    • Find(PropertyName, Value): PropertyName 是在struct中用于搜索的属性名称(必须是'Name'类型), Value 是要搜索的值。 返回在数组中第一个匹配指定的属性名 PropertyName 的值的struct的索引,如果没有找到,返回-1。 Value 可以是任何有效的表达式。
  • Sort(SortDelegate): 使用 SortDelegate 来适当地对数组的内容排序。 SortDelegate 的签名应该和以下显示的一样:
    • delegate int ExampleSort(ArrayType A, ArrayType B) { return A < B ? -1 : 0; } // 一个负数返回值预示着应该交换这些项。

长度变量

动态数组也有一个变量叫 Length ,它是指动态数组的当前长度(元素的个数)。要想访问Length,通过使用我们的示例数组,我们可以这样操作: IntList.Length 。
 我们不仅能读取这个Length变量,并且我们可以直接设置它,从而允许我们修改数组中元素的数量。当您直接修改Length变量时,在数组长度中的所有改变都在数组的末端发生。比如,如果我们设置 IntList.Length = 5,然后我们再设置IntList.Length = 10,那么我们刚刚添加的额外的5个元素会添加到数组的末端,同时保持我们原始的5个元素及其它们的值。如果我们降低Length,元素也会被从数组的末端拿掉。注意当您想一个数组增加元素时,不管是通过Insert()函数还是通过增加长度,元素都会被初始化为它的变量类型的默认值(ints为0,类的引用为None等)。值得注意的是您也可以通过设置元素的索引比当前的Length值大来增加动态数组的长度。这将和您设置Length的值为较大的值来扩展数组是一样的。

OldLength = Array.length 
Array.Length = OldLength + 1
Array[OldLength] = NewValue

Array[Array.Length] = NewValue 

Array.AddItem(NewValue) 

所有这些都是同一个操作的等价形式。

注意,您不能同时增加数组的长度并访问数组的成员。

Array[Array.length].myStructVariable = newVal

这是无效的。

注意 – 动态数组的成员Length是不能通过'++', '--', '+=', or '-='来进行增量/减量运算的,也不能将Length作为一个输出参数传递给一个函数(那个函数能够改变它的值)。由于这样做使Length不再是精确的,从而会导致内存泄露和崩溃;仅能通过使用 '=' 操作符来设置Length(并设置设置一个元素所在的索引大于Length)来适当地修改动态数组的实际长度。

注意: 不支持 array<bool> 类型!

最后需要注意的是 - 动态数组是 不能 复制(注意这个"复制"是指Replicate, 不是Copy)的。您可以通过可以复制数组的函数来解决这个问题,并且具有两个参数:一个是动态数组的一个索引及那个索引处所存储的值。然而,你也必须要考虑在客户端和服务器的一次更新时间间隔内元素不一样的后果。

迭代动态数组

动态数组现在支持 foreach= 操作符来进行简单的迭代操作。 基本语法是:

foreach ArrayVariable(out ArrayItem, optional out ItemIndex)
{
   ...
}

ArrayItem 必须和数组中的元素是同一类型。如果提供了属性,每次迭代都将索引值进行增量计算并输出元素项及其索引值。

function IterateThroughArray(array SomeArray)
{
    local string ArrayItem;
    local int Index;
    foreach SomeArray(ArrayItem)
    {
       `log("Array iterator test #1:"@ArrayItem);
    }
    foreach SomeArray(ArrayItem,Index)
    {
        `log("Array iterator test #2:"@ArrayItem@Index);
    }
}

Structs(结构体)


UnrealScript struct是把一组变量一起塞入到一个新类型称为struct的超级变量的一种方法。UnrealScript structs和C语言中的结构体很像,它可以包含变量、数组及其它的结构体,但UnrealScript structs中不可以包含函数。

关于在UnrealScript中使用struts相关的性能消耗方面的信息,请参照UnrealScript Structs(结构体)?页面。

Struct(结构体)定义

在您声明一个struct变量之前,您必须定义要使用的结构体。它的定义由 struct 关键字及后面跟随的结构体名称构成。然后,在花括号{}内,使用和声明任何其他实例变量一样的方法来声明构成结构体的变量。结束花括号的后面必须有分号。

以下是个向量结构体定义的示例:

// A point or direction vector in 3D space.
struct Vector
{
	var float X;
	var float Y;
	var float Z;
};

Structs(结构体)也可以指定它们所包含的变量的默认值。这通过在结构体定义中添加 structdefaultproperties 代码块来玩成。比如,如果您想事先定义 Vector 结构体中的每个变量的起始值为 1.0 ,那么您可以这样定义该结构体:

// A point or direction vector in 3D space.
struct Vector
{
	var float X;
	var float Y;
	var float Z;

	structdefaultproperties
	{
		X=1.0
		Y=1.0
		Z=1.0
	}
};

关于结构体成员的默认属性的信息,请参照UnrealScript默认属性页面的 Struct(结构体)默认值?部分。

Struct (结构体)修饰符

Structs也具有少量几个可以影响struct的所有实例的修饰符。修饰符在定义中位于 struct 关键字和结构体名称之间。

atomic
意味着这个struct要一直作为一个单独的单元进行序列化;如果在struct中的任何属性和它的默认值不同,那么struct中的所有元素都将被序列化。
atomicwhencooked
仅在使用已烘焙的包的数据时才应用'atomic'标志。
immutable
意味着这个结构体使用二进制序列化(减少磁盘空间占用并提高序列化性能);在没有增加包的版本的情况下从这个struct中增加/移除成员是不安全的。
immutablewhencooked
仅当使用已烘焙的包数据进行工作时才能应用'immutable'标志。
strictconfig
意味着当一个struct属性有'config/globalconfig'修饰符时,仅在这个结构体中标记为config/globalconfig的属性才能被从.ini文件中读取。(如果没有此标志,在struct中的所有属性都是可配置的)

声明Struct(结构体)变量

一旦您定义了一个struct,你便可以开始定义那个struct类型的特定变量了:

// Declare a bunch of variables of type Vector.
var Vector Position;
var Vector Destination;

使用Struct(结构体)变量

要想访问struct中的分量 ,请使用以下代码:

function MyFunction()
{
	Local Vector A, B, C;

	// Add some vectors.
	C = A + B;

	// Add just the x components of the vectors.
	C.X = A.X + B.X;

	// Pass vector C to a function.
	SomeFunction( C );

	// Pass certain vector components to a function.
	OtherFunction( A.X, C.Z );
}

你可以像操作其它变量一样来操作Struct变量: 你可以赋值变量给它们、也可以传递它们给函数、而且您也可以访问它们的成员。

在Object类中定义了几个Structs,这些在整个的Unreal将一直会使用。你必须熟悉它们的操作,因为它们是脚本的基础构建模块。

Vector
在空间中的一个唯一的三维点或者向量,具有X、 Y、Z分量。
Plane
在三维空间内定义了一个的唯一的平面。平面是通过它的X、Y、Z分量(假设它们都是归一化的)加上它的W分量来定义的,W代表了沿着平面的法线平面到原点的距离 (它是从平面到原点的最短的线)。
Rotator
一个rotation(旋转量)定义了一个唯一的正交坐标系统。一个rotator包括Pitch(倾斜度)、Yaw(偏转度)及Roll(旋转度)分量。
Coords
在三维空间中的任意一个坐标系统。
Color
一个RGB颜色值。
Region
定义了关卡中的一个凸起区域。

枚举型


在UnrealScript中枚举类型的存在,可以方便地声明能够包含一串关键字中的任意一个值的变量。比如,actor类包含着枚举变量 EPhysics ,它描述了Unreal要应用到actor上的物理。这个物理可以设置为已经预先定义的值中的一个,比如 PHYS_None=、 =PHYS_Walking=、  =PHYS_Falling 等。

在内部,枚举变量是作为字符变量存储的。在设计UnrealScript时,并没有认为枚举类型是必需的,但是当看到一个actor的物理模型被设置为 PHYS_Swimming 而不是(比如) 3 ,发现它使代码变得如此易读。

这里是定义枚举类型的示例代码。

// Declare the EColor enumeration, with three values.
enum EColor
{
   CO_Red,
   CO_Green,
   CO_Blue
};

// Now, declare two variables of type EColor.
var EColor ShirtColor, HatColor;

// Alternatively, you can declare variables and
// enumerations together like this:
var enum EFruit
{
   FRUIT_Apple,
   FRUIT_Orange,
   FRUIT_Bannana
} FirstFruit, SecondFruit;

在Unreal代码中,我们经常要声明枚举值,像 LT_SteadyPHYS_Falling 等,而不是简单地声明为"Steady" 或 "Falling"。 这只是编码风格的问题而不是语言的要求。

UnrealScript仅在枚举类型定义的类及其子类中可以识别没有明确枚举变量名的枚举标签(比如 FRUIT_Apple )。 如果你需要引用一个在类的层次的其它地方定义的枚举标签,你必须使它符合要求:

FRUIT_Apple         // If Unreal can't find this enum tag...
EFruit.FRUIT_Apple  // Then qualify it like this.

枚举值可以用作为一个静态数组的大小。另外,静态数组通过在声明中使用枚举型名称可以声明一个和枚举变量中包含的元素数量一样的静态数组。

var int MyIntArray[EFruit];

常量


在UnrealScript,你几乎可以为所有的数据类型来指定常量值:

  • 整型和字节型常量可以使用简单的数字来指定,比如 123 。=123=. 如果你必须以16进制的方式来指定一个整型或字节型常量,使用: 0x123
  • 使用十进制指定浮点型常量: 456.789
  • 字符串常量必须加上双引号,比如: "MyString"
  • Name常量必须加上单引号,比如: 'MyName'
  • Vector常量要像这样来了包含X, Y, 和 Z的值: vect(1.0,2.0,4.0)
  • Rotator常量要像这样来包含Pitch, Yaw, 和 Roll的值: Rot(0x8000,0x4000,0)
  • =None=常量指向"no object(空对象)"(或者等同地"no actor(空actor)")
  • =Self=常量指向"this object(对象本身)"(或等同地,"this actor(actor本身)"),也就是正在执行的脚本所属的对象。
  • 一般对象的常量通过用对象的类型并跟随带单引号的对象的名称来指定,比如: texture'Default'
  • EnumCount=指定了一个枚举类型的元素个数,比如: =ELightType.EnumCount
  • ArrayCount=指定了一个静态数组中的元素的个数,比如: =ArrayCount(Touching)

你可以使用"const"关键字来声明一个常量,以后便可以通过常量的名称来引用了。 比如:

const LargeNumber=123456;
const PI=3.14159;
const MyName="Tim";
const Northeast=Vect(1.0,1.0,0.0);

常量可以在类或structs中定义。

如果要访问在另一个类中定义的常量,请使用"class'classname'.const.constname"语法,比如:

class'Pawn'.const.LargeNumber

Object和actor引用变量


你可以声明一个指向一个actor或object的变量,像这样:

var actor A;	// An actor reference.
var pawn P, Q;	// A reference to an actor in the Pawn class.
var texture T;	// A reference to a texture object.

上面的变量"P"是一个到Pawn类的一个actor的引用。这个变量可以指向属于Pawn的子类的任何actor。比如,P可以指向一个Brute,或者一个Skaarj或Manta。它可以是任何类型的Pawn。然而,P永远不能指向一个Trigger actor(因为Trigger不是Pawn的子类)。

使变量指向一个actor从而获得便利的例子是在Pawn类中的Enemy变量,它指向Pawn正在试图攻击的actor。

当您有一个指向actor的变量时,你可以访问那个actor的变量并且调用它的函数。比如:

// Declare two variables that refer to a pawns.
var pawn P, Q;

// Here is a function that makes use of P.
// It displays some information about P.
function MyFunction()
{
   // Set P's enemy to Q.
   P.Enemy = Q;

   // Tell P to play his running animation.
   P.PlayRunning();
}

指向actors的变量通常或者指向一个有效的actor(任何在关卡中实际存在的actor)或者指向 None 值。None等同于C/C++中的 NULL 指针。然而,在UnrealScript中访问具有 None 引用的变量和函数是安全的;结果通常为0。

注意一个object 或 actor引用是“指向”另一个actor 或 object,它并不“包含”一个真正的actor 或 object对象。在C语言中,一个actor引用等同于指向一个AActor类的对象的指针(在C语言中,你会称它为AActor*)。例如,你可以在世界中有两个鬼怪(monsters)Bob和Fred,它们相互打斗。Bob 的"Enemy"变量将“指向”Fred,并且Fred的"Enemy"变量将“指向”Bob。

和C语言中的指针不同,UnrealScript的对象引用总是安全的可靠的。一个对象引用指向一个不存在的对象或者无效的对象是不可能的(除了特殊情况: None 值)。在UnrealScript中,当一个actor被销毁,那么它的所有引用将被设置为 None

请参照脚本间的通信部分获得关于如何使用它们在一些对象和其他对象之间进行通信的详细信息。

类引用变量


在Unreal中,类就像actors、textures(贴图)及 sounds(声音)一样是对象。 Class 对象属于名称为"class"的类。 在很多情况下,您将需要存储一个到类对象的引用,以便您可以产生一个属于那个类的actor(在编译时不知道那个类是什么)。 比如:

var() class C;
var actor A;
A = Spawn( C ); // Spawn an actor belonging to some arbitrary class C.

现在,一定不要搞乱类C和属于类C的对象O(作为类C的一个“实例”)的角色作用。 打一个不太靠谱的比喻,一个类就像一个胡椒粉的研磨工,而那个类的实例就像是胡椒粉。 你可以使用胡椒粉的研磨工(类)来转动磨制机器的曲柄(调用Spawn函数)来创建胡椒粉(类的对象)…但是,一个胡椒粉研磨工(一个类)不是胡椒粉(属于这个类的对象),所以你一定不要尝试去吃它!

当定义一个引用这个类对象的变量时,你可以有选择性地使用语法 class<metaclass> 来限制这个类不能被 metaclass 类型(及它的子类)的变量所引用。 比如,在以下声明中:

var class ActorClass;

变量ActorClass仅能引用继承类"actor"的类。 这对改善编译时的类型检查是有帮助的。比如,Spawn函数采用一个类作为参数,但是仅当这个类是Actor的子类时才有效, class<classlimitor>语法使编译器来执行那个要求。

关于使用动态对象类型转换,你可以这样来动态地转换类的类型:

// casts the result of SomeFunctionCall() a class of type Actor (or subclasses of Actor)
class( SomeFunctionCall() )

类型转换


类型转换是指将一个值从一种类型转换为另一种类型的过程,一般用于将该值赋给将要转换到的变量类型的情况。对于简单数据及类似于对象引用这样的较复杂的数据类型来说,将一个值从一个种类型转换为另一种类型是非常有用的。但是,需要记住的是在类型转换过程中可能会丢失数据。不同类型的数据具有不同的精确级别,将一个较高精确级别的数据类型转换为一个较低级别的类型时将会导致丢失额外的精度位数。

类型转换有两种形式: 隐性转换或显性转换。

隐性类型转换

某些变量数据类型(一般是数值数据类型 - byteintfloat )支持彼此间的自动数据类型转换。这称为隐性类型转换,因为您正在转换数据类型但是却没有显示地说明要转换到的数据类型。当您将一种类型的值或变量分配给另一种类型的变量时执行隐性类型转换。

比如:

var int IntVar;
var float FloatVar;

...

IntVar = 2;		// IntVar holds the value 2
FloatVar = 4.25;	// FLoatVar holds the value 4.25

...

IntVar = FloatVar;	// IntVar now holds the value 4

FloatVarIntVar 是不同的类型,但是您可以将其中的一种类型的值赋予另一个类型的变量,因为 intfloat 彼此间支持隐性类型转换。

显性类型转换

尽管数值类型可以进行隐性类型转换,但其他类型的数据需要声明要转换到的类型来进行显性类型转换。并不是所有类型都可以通过显性地类型转换为任何其他类型的数据。被转换的数据类型必须支持转换到的目标类型,否则编译器将会抛出错误。

当显性地类型转换一个值时,您必须要指明要转换到的类型,并在后面的圆括号内指出要转换的值。基本语法是:

TypeToCastTo(ValueToCast)

假设您有个 Vector(向量) 变量,您想将其显示为 String(字符串) 。因为 Vector(向量) 数据类型支持显示地转换为 String(字符串) 类型,所有以下代码是完全有效的:

var Vector Offset;
var String OffsetText;

...

Offset = vect(1.0, 2.5, 5.0);	//Offset now holds the values X=1.0, Y=2.5, Y=5.0
OffsetText = String(Offset);	//OffsetText now holds the value "1.0,2.5,5.0"

显性类型转换支持的类型

string(字符串型)
String 数据类型支持转换为以下类型:
  • Byte, Int, Float - String 存放的数值将会被转换为真正的数值型数值。如果 String 的值不包含一个数值,那么根据要转换到的类型的不同,类型转换的结果将是 00.0
  • Bool -将 String 的值转换为 TRUEFALSE 。如果 String 包含 "True""False" (不区分大小写),那么文本将会被直接转换为等价的 Bool 值。如果这些值都不存在,那么 String 的值将首先被转换为数值型值(遵循上面描述的规则),然后如果数值型值为 0 ,则将其转换为 BoolFASLE ,其他的任何值则转换为 TRUE
  • Vector, Rotator - 将存放 VectorRotation 类型值(三个数值之间由逗号分割,比如“0.5,23.64,18.43”)的文本形式的 String(字符串) 转换为指定的目标类型数据。 对于 Vector 转换来说, String(字符串) 中的数值将会被转换为具有两位小数位精确度的 Float(浮点型) 值。对于 Rotator 转换来说, String(字符串) 中的数值将会被删减,或者删除所有小数位,并将其转换为 Int(整型) 值。
Bool
Bool 数据类型支持被转换为以下数据类型:
  • String - 将 Bool 型的 TRUEFALSE 值分别转换为 "True""False"
  • Byte, Int, Float - 将 Bool 型的 TRUEFALSE 值分别转换为数值 10
Byte, Int, Float, Vector, Rotator
这些数值型数据类型支持转换为以下类型:
  • String - 转换为数值的文本形式。对于 VectorRotator 来说,文本形式是三个数值( XYZPitchYawRoll ),三个值之间由逗号分隔。
  • Bool - 将数值转换为 BoolTRUEFALSE 。任何非零值会被转换为 TRUE ,而值0将会被转换为 FALSE 。对于 VectorRotator 来说,每个分量的值都是0则转换为 FALSE 。如果有非零值存在,结果将是 TRUE
Name
Name 数据类型支持转换为以下类型:
  • String - 将 Name 的文本值转换为一个 STRING 文本值。
Vector
Vector 数据类型支持转换为以下类型:
  • Rotator - 将从世界原点处到 Vector 坐标指定位置处的方向向量转换为对应那个方向的 RotatorPitchYaw 值。==Roll== 值将总是为 0
Rotator
Rotator 数据类型支持转换为以下类型:
  • Vector - 将==Rotator==的 PitchYawRoll 值转换为从原点开始指向旋转向量方向的 Vector 的坐标。
Object Reference
Object Reference 数值型数据类型支持转换为以下类型:
  • Int - 将 Object Reference 转换为唯一的 Int 值。
  • Bool - 如果 Object Reference 保存了一个有效的引用那么则返回 TRUE ,否则如果对象引用的值是 None 则返回 FALSE
  • String - 将 Object Reference 转换为文本形式,也就是将正在引用的 ObjectActorName 属性转换为字符串 (转换 Name 为一个 String 数据) ,否则如果没有引用任何 Object ,则将转换为 "None"
  • Object Reference - 假设两个类是相关的,那么一个类的 Object Reference 可以从该类转换为另一个类。请参照转换对象引用部分来获得关于这种类型转换的详细信息。

转换对象引用

就像上面的简单数据类型的转换函数一样,在UnrealScript中你可以在各种类型之间转换actor和object引用。比如,所有的actors有一个叫"Target"的变量,它是到另一个actor的引用。假如您正在写一个脚本,在脚本中您需要检查并查看Target是否属于"Pawn" actor类的,并且你需要对您的target做一些特殊的处理,但仅当它是一个pawn类时才有效--比如,您需要调用Pawn函数的其中一个。actor的类型转换操作符可以让您完成这个目的。这里是一个示例:

var actor Target;
//...

function TestActorConversions()
{
	local Pawn P;

	// Cast Target to Pawn and assign the result to P.  If Target is not a Pawn (or subclass of Pawn), then the value assigned to P will be None.
	P = Pawn(Target);
	if( P != None )
	{
		// Target is a pawn, so set its Enemy to Self.
		P.Enemy = Self;
   	}
   	else
   	{
	   	// Target is not a pawn.
   	}
}

要想执行actor转换,需要书写类的名称并在后面加上您希望转换的actor表达式,并使用圆括号括起。根据这个转换是否合理,转换将或者成功或者失败。在上面的例子中,如果您的Target指向的是一个Trigger对象而不是一个Pawn,表达式Pawn(Target)将会返回"None"值,因为不能将一个Trigger转换为Pawn。然而,如果您的Target指向一个Brute对象,转换将会成功并返回那个Brute,因为Brute是Pawn的子类。

因此,actor类型转换有两个目的: 第一,你可以使用它们来判断某个actor引用是否属于某个类。第二,你可以使用它们来将一个actor引用从一个类转换为一个更加明确的类。注意这些转换不会影响您正在转换的actor—它们只是使UnrealScript将对待那个actor引用就像它是一个更加明确的类型一样并且允许您访问这个更加子类中所声明的属性和方法。

另一个类型转换的列子是在Inventory脚本中。每个Inventory actor由一个Pawn所有,尽管它的Owner变量可以指向任何Actor(因为Actor.Owner是一个Actor类型的变量)。所以在Inventory代码中我们会将常看到将一个Owner转换为Pawn类型的现象,比如:

// Called by engine when destroyed.
function Destroyed()
{
	// Remove from owner's inventory.
	if( Pawn(Owner)!=None )
    	Pawn(Owner).DeleteInventory( Self );
}