现在的位置: 首页 > 综合 > 正文

UnrealScript语言参考

2014年03月01日 ⁄ 综合 ⁄ 共 19782字 ⁄ 字号 评论关闭

档概要: UnrealScript 介绍和简要参考。最初作者是Tim Sweeney (EpicGames)

 

内容

 

 

 

介绍

 

快速链接

请一定要查看UnrealScript 的快速参考表掌握UnrealScriptTOC指南

 

本文档的目的

这是一篇描述UnrealScript编程语言的技术文档。它不是指南,也没有提供有用的UnrealScript代码的详细例子。要获得UnrealScript的例子,读者可以参考引擎的源代码,它提供了成千上万行的有效代码,用来解决许多例如AI、运动、武器装备和触发事件等很多问题。最好的入门方式是查看"Actor"、"Object(物体)"、 "Controller(控制器)"、 "Pawn(士兵)" "Weapon(武器)"的脚本。

本文档假设读者使用过C/C++或 Java编程语言、熟悉面向对象程序设计、已经玩过Unreal的游戏并使用过UnrealEd的编辑环境。

对于是面向对象程序设计的新手的程序员,我强烈推荐您去Amazon.com或者书店买一本介绍java编程方面的书。Java和UnrealScript很相似,并且由于它的干净和简单的方法使它成了一种值得学习的极好的语言。

 

UnrealScript的设计目标

UnrealScript是为开发团队和第三方Unreal开发人员创建的,是一种强大的内置的编程语言,它自然地满足了游戏编程的需要和细小差别。

UnrealScript的主要设计目标:

 

  • UnrealScript支持传统的编程语言没有提到的时间、状态、属性、网络等主要的概念。这大大地简化了UnrealScript代码。基于C/C++的AI和游戏逻辑编程的主要复杂性是处理要花费一定量的游戏时间来完成的事件以及处理依赖物体状态的各个方面的事件。在C/C++中,这将会导致冗长的混乱的代码,使代码难于书写、理解、维护和调试的。UnrealScript包含了对时间、状态和网络复制的内部支持,这大大地简化了游戏编程。

 

  • 提供一种像Java类型编程语言一样简单的、面向对象的并在编译时进行错误检查的语言。就像Java为Web开发人员提供了一个干净的开发平台,UnrealScript为3D游戏提供了一个同样干净的、简单的、强大的编程语言。UnrealScript从Java语言中衍生的主要编程观念有:

    • 没有指针并自动进行垃圾回收的环境;
    • 一个简单的单继承类图;
    • 编译时进行强类型检查;
    • 安全的客户端执行的"sandbox"
    • 像C/C++/Java代码一样熟悉的外观和感觉。

 

  • UnrealScript为了在游戏对象和交互方面而不是位和像素方面提供丰富的高层次的编程语言,所以在设计上必须有一些妥协,我们为了获得开发的简单性和强大性,从而牺牲了执行速度。毕竟, Unreal的底层的、对性能起重要作用的代码是由C/C++书写的,在那里所获得的性能提高的价值超出了所增加的复杂性。UnrealScript是在那个层次的基础上进行运作的,在物体和交互性的层次上而不是位和像素的底层上。-

在UnrealScript开发的早期,我们探索了几个主要的不同的编程语言范例,然后又放弃了,最终开发出了目前的UnrealScript。首先,我们研究使用Sun 和 Microsoft为Windows设计的Java VM(虚拟机) 作为Unreal脚本语言的基础。但最终证明在Unreal的情境中Java并没有提供比C/C++更大的编程好处,反而由于缺乏所需要的语言功能(比如 运算符重载)而增加了一些令人沮丧的限制,另外也证明由于VM过多的任务转换开销和Java垃圾回收器在处理大的对象图形时的低效率导致运行速度特别的慢。其次,我们设计了基于Visual Basic变量的UnrealScript初期实现,它可以工作的很好,但是对于已经习惯于C/C++的程序员来说,它不是那么友好。最终基于我们想将游戏的特定概念映射到语言定义本身的愿望以及获得速度和熟悉度的需要,我们决定将UnrealScript设置为基于C++/Java变种的语言。结果证明这是一个好主意,因为它在很多方面大大地简化了Unreal代码。

 

虚幻引擎3中UnrealScript的新功能

对于已经熟悉UnrealScript的人来说,这里是一个自虚幻引擎2后在UnrealScript中所发生的主要改变的简短概要。

 

  • Replication(复制)-在UE3中replication(复制)语句已经改变:

    • 现在复制(replication)语句块只适用于变量。
    • 函数复制(replication)现在通过以下方法定义:function specifiers (Server, Client, Reliable )
  • 状态栈 - 你现在可以使状态压入栈或弹出栈。
  • UnrealScript处理器 - 支持宏和条件编译。
  • 调试功能 - 添加了新的和调试相关的功能。
  • 默认属性 - defaultproperties块的处理已经被改变/改进。
    • 默认值 - structs现在也可以有默认属性。
    • 不再允许给配置或者局部变量设定默认值。
    • 在运行时系统中是随机的,它不再允许执行class'MyClass'.default.variable = 1的操作。
  • 动态数组 - 动态数组现在有一个新功能 find() ,用于查找一个元素的索引。
  • 动态数组迭代器 - Foreach操作符现在可以应用于动态数组。
  • Delegate 函数参数 - UE3现在允许 delegates作为函数的传递参数。
  • 接口 - 添加了对接口的支持
  • 从其它的类中访问常量:class'SomeClass'.const.SOMECONST
  • 支持多个定时器
  • 默认的函数参数值 - 现在可以指定操作函数参数的默认值。
  • 支持工具提示- 如果在UnrealScript中属性声明的上面有一个=/** tooltip text */=形式的注释,则在编辑器的属性窗口中,当您将鼠标放到一个属性上时可以显示工具提示文本。
  • 支持元数据 - 通过将属性和各种类型的元数据相关联,扩展了in-game(游戏中)和in-editor(编辑器中)的功能。

 

代码结构示例

这个示例说明了一个典型的简单的UnrealScript类,并且它囊括了UnrealScript的语法和功能。注意由于该文档没有和代码同步,所以这个代码可能和现在的Unreal源代码的呈现不一样。

 

//=====================================================================
// TriggerLight.
// 一个可以通过触发进行开关的光源
//=====================================================================
class TriggerLight extends Light;
 
//---------------------------------------------------------------------
// 变量
 
var() float ChangeTime; //光源从开到关所需要的时间
var() bool bInitiallyOn; //它在最初是否是亮的
var() bool bDelayFullOn; // 在到完全的点亮之前是否有延迟
 
var ELightType InitialType; // 光源的初始类型
var float InitialBrightness; //光源的初始亮度
var float Alpha, Direction;
var actor Trigger;
 
//---------------------------------------------------------------------
//引擎函数
 
//在游戏开始播放时调用
function BeginPlay()
{
   // 记忆光源的初始类型并为它设置一个新的类型
   Disable( 'Tick' );
   InitialType = LightType;
   InitialBrightness = LightBrightness;
   if( bInitiallyOn )
   {
      Alpha = 1.0;
      Direction = 1.0;
   }
   else
   {
      LightType = LT_None;
      Alpha = 0.0;
      Direction = -1.0;
   }
}
 
// 当时间经过时调用
function Tick( float DeltaTime )
{
   LightType = InitialType;
   Alpha += Direction * DeltaTime / ChangeTime;
   if( Alpha > 1.0 )
   {
      Alpha = 1.0;
      Disable( 'Tick' );
      if( Trigger != None )
         Trigger.ResetTrigger();
   }
   else if( Alpha < 0.0 )
   {
      Alpha = 0.0;
      Disable( 'Tick' );
      LightType = LT_None;
      if( Trigger != None )
         Trigger.ResetTrigger();
   }
   if( !bDelayFullOn )
      LightBrightness = Alpha * InitialBrightness;
   else if( (Direction>0 &amp;amp;amp;&amp;amp;amp; Alpha!=1) || Alpha==0 )
      LightBrightness = 0;
   else
      LightBrightness = InitialBrightness;
}
 
//---------------------------------------------------------------------
//公有状态
 
//触发打开光源
state() TriggerTurnsOn
{
   function Trigger( actor Other, pawn EventInstigator )
   {
      Trigger = None;
      Direction = 1.0;
      Enable( 'Tick' );
   }
}
 
//触发关闭光源
state() TriggerTurnsOff

{
   function Trigger( actor Other, pawn EventInstigator )
   {
      Trigger = None;
      Direction = -1.0;
      Enable( 'Tick' );
   }
}
 
//触发切换光源的开关
state() TriggerToggle
{
   function Trigger( actor Other, pawn EventInstigator )
   {
      log("Toggle");
      Trigger = Other;
      Direction *= -1;
      Enable( 'Tick' );
   }
}
 
// 触发控制光源
state() TriggerControl
{
   function Trigger( actor Other, pawn EventInstigator )
   {
      Trigger = Other;
      if( bInitiallyOn ) Direction = -1.0;
      else Direction = 1.0;
      Enable( 'Tick' );
   }
   function UnTrigger( actor Other, pawn EventInstigator )
   {
      Trigger = Other;
      if( bInitiallyOn ) Direction = 1.0;
      else Direction = -1.0;
      Enable( 'Tick' );
   }
}

在这个脚本中要看的主要元素是:

 

  • 类的声明。每个类"extends" (继承)一个父类,并且每个类属于一个"package(包),",一组对象一起发布。属于一个类的所有功能和变量,仅属于那个类的actor(物体)可以访问。没有整个系统范围可以使用的全局函数或变量。More Details更多详情

 

  • 变量声明。UnrealScript支持多种变量类型,包括大多数基于C/Java的类型、对象引用、structs (结构体)和数组。另外,变量可以被设置成为可以编辑的属性,这样设计人员在UnrealEd中即使不用任何编码就可以访问这些变量了。这些属性通过使用 var() 语法来指定,而不是 varMore Details更多详情
  • 函数。函数可以有一系列的参数,并且可以随意地返回一个值,也可以有局部变量。某些函数是由虚幻引擎本身调用的(例如 BeginPlay),有些是由其它的脚本代码进行调用的。(比如Trigger)。

 

  • 代码。支持所有的标准的C和Java关键字,比如 for=、 =while=、 =break=、 =switch=、 =if 等等。

 

  • Actor和object(对象)引用。这里你看到了几个在另一个对象中使用对象引用调用一个函数的情况。

 

  • 关键词"state"。这个脚本定义了几个"states",它们由函数、变量和仅当这个物体在那个状态时所执行的代码组成。

 

  • 注意:在UnrealScript中,所有的关键词、变量名、函数和对象名都是大小写不敏感的。对于UnrealScript来说,=Demon=, demON, 和 demon 是同样的事情。

 

Unreal虚拟机

Unreal虚拟机有以下几部分组成:服务器、客户端、渲染引擎及引擎支持代码。

Unreal控制着所有的玩家和物体间的游戏性和交互。在一个单人游戏中,Unreal客户端和Unreal服务器在同一台机器上运行;在一个网络游戏中,有一个机器用于专用服务器;所有连接到这个机器上的玩家是客户端。

所有的游戏播放都发生在一个"关卡"中,它是一个包含着几何体和物体的独立环境。尽管UnrealServer可以同时运行多个关卡,每个关卡独立运作并且彼此屏蔽:物体(actors)不能在不同关卡间穿行,而且一个关卡中的物体不能和另一个关卡中的物体进行交流。

在地图中的每个物体都可以或者在玩家的控制下(在网络游戏中可以有很多玩家)或者在脚本的控制下。当一个物体在脚本的控制下时,那么该脚本完全地定义了物体如何移动及如何与其它物体进行交互。

对于世界中所有这些物体的跑动、执行脚本、事件发生,你也许会问它们是如何能理解UnrealScript的执行流程哪。答案如下所示:

为了管理时间,Unreal将游戏播放的每秒钟分隔为"Ticks"。一个Tick是关卡中所有物体更新所使用的最小时间单位。一个tick一般是一秒钟的1/100到 1/10。Tick时间仅受到CPU功率的限制,机器速度越快,tick持续时间越短。

在UnrealScript中的某些命令的执行只需要使用零tick(也就是:它们的执行没有占有任何游戏时间),也有些命令需要占用很多ticks。需要占用游戏时间的函数称为"latent functions(潜伏的函数)"。一些latent functions函数的例子包括 Sleep , FinishAnim , and MoveTo 。UnrealScript中的Latent functions仅可以从在一个状态的代码中被调用(所以也称作"state code(状态代码)"),而不能从一个函数的代码中(包括在一个状态中定义的函数)被调用。

当一个actor在执行一个latent函数,那个actor的状态执行不会继续直到latent函数执行完毕。然而,其它的actor或者VM可能会调用actor内部的函数。最终的结果是所有的UnrealScript的函数可以在任何时间被调用,甚至在latent 函数没有执行完毕的情况下。

按照传统的编程术语来说,UnrealScript就像在关卡中的每个物体有它们自己的执行"thread(线程)"一样工作。在内部,Unreal不使用Windows线程,因为那将是非常低效的(Windows 95和Windows NT不能高效地处理同时发生的成千上万的线程)。然而,UnrealScript 可以模拟线程。虽然这个事实对于UnrealScript代码是透明的,但当您书写和UnrealScript交互的C++代码时则变得非常显然的。

所有的UnrealScripts将彼此独立地执行,如果有100个鬼怪正在关卡中走动,那么所有的这100个鬼怪的脚本在每个"Tick"中都正在同时地且独立地执行着。

 

对象层次

在使用UnrealScript进行工作之前,理解Unreal中物体的高层次的关系是非常重要的。Unreal的架构和其它大多数的游戏架构是有较大的背离的:Unreal是完全地面向对象的(非常像 COM/ActiveX),它有一个定义明确的对象模型,可以支持高层次的面向对象的概念比如对象图、序列化、对象生命周期和多态性。从游戏历史上来说,尽管很多游戏比如Doom和Quake,已经证明在内容方面有较大的可扩展性,但大多数游戏都被设计成为集成化的,它们的主要功能都是被硬编码的并且是在对象的层次上不能扩展的。Unreal的面向对象的形式有一个很大的好处:主要的新功能和对象类型可以在运行时添加到Unreal中,并且这个扩展是以划分子类的方式进行的,而不是(比如)通过修改一串已有的代码。这种扩展的形式是非常强大的,因为它鼓励Unreal团队共同来创建可以所有人都可以操作的改善。

Object是Unreal中所有对象的父类。在Object类中的所有函数可以在任何地方访问,因为任何东西都继承于Object。Object是一个抽象的基类,它没有做任何有用事情。所有的功能都是由子类提供,比如Texture (一个贴图),TextBuffer(文字块)和Class (它描述了其它对象的类)。

Actor(继承Object)是Unreal中所有独立运行的游戏对象的父类。Actor包含了所有的一个物体所需要的用于四处运动、和其它物体进行交互、影响环境及做其它与游戏相关的有用的事情的功能。

Pawn(继承Actor)是Unreal中所有的可以使用高层次AI和玩家控制的创造物和玩家的父类。

Class (继承 Object)是一种描述对象的类的特殊类型的object。刚看到时可能是令人疑惑的:一个类是一个对象,而其一个类描述某些的对象。但是这概念是合理的,并且在很多情况下您将会用到Class的对象。例如,当你在UnrealScript产生一个新的actor,你可能会通过Class对象来指定actor的类。

使用UnrealScript,你可以为任何Object类书写代码,但是99%的时候您都是在为从Actor继承的类来写代码。大多数有用的UnrealScript功能是游戏相关的并且是处理actors的。

每个脚本明确地对应一个类,并且脚本是通过声明类、类的父类及任何和该类相关的其它附加信息开始的。最简单的形式是:

 

class MyClass extends MyParentClass;

这里我声明了一个名为"MyClass"的新类,它继承了"MyParentClass"类的功能。另外,这个类存储在名为"MyPackage"的包中。

每个类继承它父类的所有的变量、函数和状态。然后它可以添加新的变量声明、添加新的函数(或者重写已有函数)、添加新的状态(或者为已有的状态添加功能)。

在UnrealScript中典型的设计类的方法是构造一个继承了具有您所需要的大部分功能的现有类(比如Pawn类,即所有怪物的基类)的新类(比如一个”人身牛头怪物”)。使用这个方法,你从来不需要重新发明新的东西---你可以简单地增加您想自定义的新功能,然而保持所有你不需要进行自定义的现有的功能。这个方法在Unreal中实现AI时显得尤其有用,因为在内置的AI系统中提供了大量的基础功能,您可以把它们作为您自定义的创造物的组成部分。

类的声明可以带有几个可选的影响类的修饰符:

 

Native(包名称)
意味着“这个类使用C++作为幕后支持”。Unreal期望native类在.EXE文件中包含着一个C++实现。只有native类可以声明native函数或者实现native接口。Native类必须继承于另一个native类。Native类创建一个自动生成的具有必要的 _ glue_ 的C++头文件来和脚本变量及指定函数进行交互。
NativeReplication
意味着对于该类的变量值的复制是在C++实现中处理的。仅对native类有效。
DependsOn(ClassName[,ClassName,...])
意味着ClassName是在这个类之前进行编译。ClassName必须在同一个(或前一个)包中指定一个类。多个依赖的类可以通过使用一个单独的 DependsOn 代码行并且类之间通过逗号分界来指定,或者通过为每个类使用单独的 DependsOn 来指定。

 

Abstract
声明类为一个"abstract base class(抽象的基类)"。这可以防止用户在UnrealEd的世界中添加这个类中的actor或者在游戏中创建这个类的实例,因为这个类本身没有任何意义。例如,"Actor(物体)"基类是抽象的,然而它的子类"Ladder(梯子)"不是抽象的—那么你可以在世界中放置一个Ladder,但你不可以在世界中放置一个Actor。这个关键词可以传播到内在的子类,但是不能传播到脚本的子类。

 

Deprecated
导致该类的所有对象可以被加载但不能被保存。当关卡设计者在编辑器中加载地图时,地图中任何已放置的deprecated actors的实例将会给他们产生一个警告。
Transient
说明”属于这个类的对象将永远不会被保存到磁盘上” 。 仅在和某些类型的netive类结合时才有作用,这些netive类天生不需要持久存在的比如玩家或者窗口。这个关键字可以传播到子类,子类可以使用 NotTransient 关键字覆盖这个标志。
NonTransient
取消从基类继承的 Transient 关键字。
Config(IniName)
意味着允许这个类在.ini文件中存储数据。如果在类(以"config"或 "globalconfig"声明)中有任何可配置的变量,则可以把这些变量被保存到指定的配置文件中。这个标志可以传播到所有的子类且不能取消传播,但子类可以通过重新声明 Config 关键字 并指定一个不同的IniName来改变.ini文件。正常情况下IniName指定了用于存储数据的.ini文件,但是有几个名称具有特殊的意义:

 

    • Config(Engine): 使用引擎配置文件,它的名称是您的游戏的名称后附加上"Engine.ini"。比如,ExampleGame的引擎配置文件名称是ExampleEngine.ini。
    • Config(Editor): 使用编辑器配置文件,它的名称是您的游戏名称后附加"Editor.ini"。比如,ExampleGame的编辑器配置文件名称是ExampleEditor.ini。
    • Config(Game): 使用游戏配置文件,它的名称是您的游戏名称后附加"Game.ini"。比如,ExampleGame的游戏配置文件名称是ExampleGame.ini。
    • Config(Input): 使用输入配置文件,它的名称是您的游戏名称后附加"Input.ini"。比如ExampleGame的输入配置文件是ExampleInput.ini。
PerObjectConfig
为每个对象存储这个类的配置信息,每个对象在.ini文件中有一个在该对象后以[ObjectName ClassName]的形式命名的部分。这个关键字可以传播到子类。
PerObjectLocalized
以每个对象为基础为这个类定义本地化数据,每个对象在本地化文件中都有一个在该对象后以[ObjectName ClassName]形式命名的部分。这个关键字可以传播到子类。

 

EditInlineNew
编辑器。意味着这个类的对象可以从UnrealEd的属性窗口中创建(默认行为是仅已存在的对象的引用可以通过属性窗口进行分配)。这标志可以传播到所有子类,子类可以使用 NotEditInlineNew 关键字覆盖这个标志。
NotEditInlineNew
编辑器。取消从基类继承 EditInlineNew 关键字。如果父类没有使用 EditInlineNew 关键字,则该关键字没有影响。
Placeable
编辑器。意味着这个类可以在UnrealEd中创建并可以被放置到关卡、UI scene或者kismet窗口中(依赖于类的类型)。这个标志可以传播到所有子类,子类可以通过使用 NotPlaceable 关键字覆盖这个标志。
NotPlaceable
编辑器。取消从基类继承 Placeable 关键字,意味着这个类不能放置UnrealEd中的关卡中等。
HideDropDown
编辑器。阻止这个类在UnrealEd的属性窗口的复选框中显示。
HideCategories(Category[,Category,...])
编辑器。为这个类的对象指定一个或多个应该在UnrealEd属性窗口中隐藏的类别。为了隐藏声明时的没有类别的变量,可以使用声明变量时所使用的类的名称。
ShowCategories(Category[,Category,...])
编辑器。取消从基类继承 HideCategories 关键字。
AutoExpandCategories(Category[,Category,...])
编辑器。为这个类的对象指定一个或多个应该在UnrealEd属性窗口中自动展开的类别。为了自动展开声明时的没有类别的变量,可以使用声明变量时所使用的类的名称。
Collapsecategories
编辑器。意味着这个类的属性不应该在UnrealEd的属性窗口中以类别分组。这个关键字可以传播到子类,子类可以使用 DontCollapseCategories 关键字来覆盖这个标志。
DontCollapseCategories
编辑器。 取消从基类继承 CollapseCatogories 关键字。
Within ClassName
高级。 意味着这个类的对象在没有ClassName的实例的情况下不能存在。为了创建这个类的对象,你必须指定一个ClassName的实例作为 Outer 对象。这个关键字必须紧跟在类的声明本身后面。 Inherits(ClassName[,ClassName,...]):高级。用于多重继承-指定额外的基类。多个被继承的基类可以通过使用一个 Inherits 并在多个基类之间用逗号分开来指定,或者通过为每个基类分别使用一个=Inherits= 来指定。仅对native类有效。不支持来自两个UObject-derived类的多重继承。
Implements(ClassName[,ClassName,...])
高级。指定一个或多个这个类要实现的接口类。多个接口可以通过使用一个单独的=Implements=且多个接口使用逗号分隔来指定,或者通过为每个接口类使用一个=Implements=来指定。
NoExport
高级。意味着这个类的C++声明不应该被脚本编译器包含到自动生成的C++头文件中。该C++类的声明必须在一个单独的头文件中手动地定义。

 

变量

 

变量类型

 

内置类型

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

 

var int a;               //声明了一个整型变量,
名称为"A"的
var byte Table[64];         //声明了一个64个字节的静态数组,名为"Table"的。
var string PlayerName;      // 声明了一个字符串变量,名称为"PlayerName"。
var actor Other;         //声明了一个可以被赋值为一个Actor实例的引用的变量。
var() float MaxTargetDist;   // 声明了名称为"MaxTargetDist"的一个浮点变量,并且它的值可以从UnrealEd的属性窗口中进行修改。

变量在UnrealScript能出现在两种地方:实例变量,它应用于整个对象,在类声明后或者在struct声明内立即出现。局部变量,出现在函数中,仅在函数执行时有效。实例变量使用关键字 var 进行定义。局部变量使用关键字 local 进行定义,比如:

 

function int Foo()
{
   local int Count;
   Count = 1;
   return Count;
}

这里是UnrealScript中支持的内置的变量类型:

 

  • byte(字节型): 一个字节值的范围是 0255
  • int(整型): 32位的整型值
  • bool(布尔型): 布尔值:=真= 或
  • float(浮点型): 32位的浮点数。
  • string(字符串型): 一个字符串(请查看Unreal 字符串)
  • constant(常量): 不能修改的变量。
  • enumeration(枚举型): 一个能够代表多个预先设定的整数值中其中一个值的变量。比如,在Actor脚本中定义的枚举类型ELightType描述了一个动态光源,它可以具有像 LT_None=、 =LT_Pulse=、 =LT_Strobe 等值。

 

集合数据类型

array<Type>:一个 Type 类型的数组。

struct
和C中的结构体类似,UnrealScript的structs可以让您创建包含子变量的新的变量类型。比如,两个常用的Unreal structs是由X坐标、Y坐标及Z坐标组成的 vector(向量) ;及由倾斜度、偏转度、旋转度组成的 rotator

 

Unreal类型

 

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

 

变量修饰符

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

 

config
这个变量是可以配置的。当前的值将被保存到一个ini文件中并在创建时加载。这个变量不能在默认属性中赋值。
globalconfig
和config的使用基本相同,除了不可以在子类中覆盖它所定义的变量并且它不能在默认属性中进行赋值。意味着它是常量。[这里的理解可能有歧义,解释下:config的数据可以在派生类中重写,globalconfig不可以,mark by dongbo]。
localized
这个变量的值将会定义一个局部变量,主要用于字符串。意味着是常量。在Localization Reference(局部化参考)Unreal 字符串获得关于此的更多信息。
const
把变量的内容当成一个常量。在UnrealScript,你可以读取常量的值,但是你不能对其写入值。"Const"仅用于引擎来负责更新的变量及不能从UnrealScript中安全地进行更新的变量,比如一个物体的位置(仅能通过调用MoveActor函数来进行设置)。
private
这个变量是私有的,仅能通过类的脚本来进行访问;其它的类(包括子类)不能访问该变量。
protected
这个变量仅能由此变量的类及其子类进行访问,其它类不能访问。
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的输入系统中是可以访问的,从而使输入(比如按钮的押下和操作杆的运动)能够和变量直接地进行映射。
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 or TArrayNoInit导出到头文件中。仅适用于在native类中声明的字符串和动态数组。'Init'属性不能被赋予默认值,因为当创建对象时,默认值将会被清除。(请查看 Unreal 字符串Native 字符串)

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

skip
这个修饰符仅对运算符函数参数有效。仅用于逻辑运算符比如&& 和 ||。如果一个表达式的输出已经确定则防止赋值。比如:FALSE && ++b==10 (更多详情).

 

可编辑性

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

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

 

var() int MyInteger; //在默认目录中声明了一个可以编辑的整型
                   
var(MyCategory) bool MyBool; //中声明一个可以编辑的整型"MyCategory"
                             

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

 

// MyBool在UnrealEd中是可以看见的但却不可编辑
var(MyCategory) editconst bool MyBool; 

// MyBool变量在UnrealEd中是可见的但不能编辑而且不能通过脚本来改变它的值
var(MyCategory) const editconst bool MyBool; 

// MyBool变量在UnrealEd中是可见的且可以设置,但不能在脚本中改变他的值
var(MyCategory) const bool MyBool; 

 

数组

数组使用以下语法声明:

 

var int MyArray[20]; //声明了一个长度为20的整形数组

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

 

Structs

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

你可以按照以下方法来声明一个struct:

 

//在3D空间的一个点或方向向量
struct Vector
{
   var float X;
   var float Y;
   var float Z;
};

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

 

//声明了一组Vector类型的变量
var Vector Position;
var Vector Destination;

要想访问struct中的分量 ,可以按照以下方式使用代码:

 

function MyFunction()
{
   Local Vector A, B, C;
    
   //向量相加
   C = A + B;
 
   //仅向量的X成员相加
   C.X = A.X + B.X;
 
   // 将向量C传递到一个函数中
   SomeFunction( C );
 
   //将向量的某个成员传递到函数中
   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
定义了关卡中的一个凸起区域。

 

修饰符

Structs也有少许修饰符来影响struct的所有实例。

 

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

 

枚举

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

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

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

 

//定义了一个具有三个值的枚举类型EColor。
 enum EColor
{
   CO_Red,
   CO_Green,
   CO_Blue
};
 
//现在定义EColor类型的两个变量
var EColor ShirtColor, HatColor;
 
//可替换地,你可以像这样一起声明变量和枚举类型:

var enum EFruit
{
   FRUIT_Apple,
   FRUIT_Orange,
   FRUIT_Bannana
} FirstFruit, SecondFruit;

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

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

 

FRUIT_Apple         // 如果Unreal不能找到这个枚举标签…
EFruit.FRUIT_Apple  //那么像这样来使它符合要求

 

常量

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

 

  • 整型和字节型常量可以使用简单的数字来指定,比如 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")
  • =Self=常量指向"this object"(或等同地,"this 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; //一个actor引用
var pawn P; //一个到Pawn类中的一个actor的引用
var texture T; //一个到贴图对像的引用

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

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

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

 

//声明指向一个pawn的两个变量
var pawn P, Q;
 
//这里是一个使用P对象的函数,它显示了关于P对象的信息。
function MyFunction()
{
   // 设置P的敌人为Q
   P.Enemy = Q;
 
   //告诉P播放这个跑动的动画
   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

 

类引用变量 <

抱歉!评论已关闭.