UnrealScript

維基教科書,自由的教學讀本

導言[編輯]

文檔目標[編輯]

這是一份講述UnrealScript語言的技術性文檔。這不是一個教程,也沒有提供有用的UnrealScript代碼的詳細例子。讀者可以參考虛幻引擎,它包了數萬行的UnrealScript原始碼,它解決了諸如人工智能,運動,inventory,和觸發器等問題。一個好的入手點是看"Actor", "Object", "Controller", "Pawn", and "Weapon" 的腳本。

本文假設讀者具備C/C++ 或Java的編程經驗,熟悉面向對象編程,玩過虛幻遊戲,用過虛幻關卡編輯器(UnrealEd)。

對於OOP(面向對象編程)新手,強烈建議去書店買本Java的書。Java和UnrealScript非常相似,它清晰、簡潔、優秀。

UnrealScript的設計目標[編輯]

由於遊戲編程的自然需要和細微差別UnrealScript被創建出來,為開發團隊和第三方虛幻開發商提供了一個強大的內置程式語言。

UnrealScript的主要設計目標是:

  • 支持傳統程式語言沒有解決的時間,狀態,屬性的網絡化。這大大簡化了UnrealScript的代碼。編寫基於人工智能和遊戲邏輯的程序,主要運用事件交互技術,這些事件採取一定的遊戲時間完成,並且事件非常依賴對象狀態,這讓網絡化問題極度複雜化。在c/c++中書寫、理解、維護和調試這樣的代碼是非常困難的。UnrealScript天生支持時間、狀態、網絡複製大大簡化了遊戲編程。
  • 提供Java編程風格,簡單、基於對象的、編譯時錯誤檢查的特性。就象Java為Web程式設計師帶來了清晰、簡潔的編程平台一樣,UnrealScript為3D遊戲程式設計師提供了一個同樣清晰、簡潔、可靠的程式語言。從Java繼承的主要編程概念如下:
    • 具有自動垃圾收集的無指針環境;
    • 一個簡單的類單一繼承機制;
    • 強壯的編譯時類型檢查;
    • 安全客戶端執行的「沙盒」;
    • 熟悉的c/c++/java代碼外觀和感受;
  • 提供遊戲對象豐富的高層互動,而不是底層的位和像素。在設計權衡時,由於UnrealScript工作在對象互動層,而不是底層的位和像素,因此在UnrealScript中,犧牲了性能選擇了簡單性和功能。而在底層和性能的關鍵代碼是用c/c++寫的,在這些地方增加性能獲得的好處超過了增加複雜性得到的壞處,選擇了性能犧牲了簡單性和功能。

在UnrealScript的早期發展期間,我們探索過幾個主要的不同的編程模式。首先,我們研究把Sun和微軟的Java虛擬機的Windows版本,作為虛幻腳本語言的基礎。證明了在虛幻中Java由於缺乏必要的語言特性(如運算符重載),而擁有令人沮喪的限制,同時在巨型圖形對象的情況中,虛擬機任務切換和Java垃圾收集器效率過低,慢得無法接受,Java沒有提供不在c/c++中編程的優點。其次,我們嘗試使用VB的一個早期修改版作為UnrealScript的實現,效果良好,但可惜的是它不符合c/c++程式設計師的習慣。最終,基於對速度和熟悉感的期望,我們決定UnrealScript採用c++/java的一個修改版來實現,同時融入遊戲特有的概念到語言的定義中。

虛幻引擎3的新內容[編輯]

熟悉UnrealScript的讀者們,可以在這裏找到自虛幻引擎2後的重大改變。

  • 複製-複製語法在UE3中有以下變化:
    • 複製塊現在只用於變量
    • 複製函數現在由函數說明符定義(Server, Client, Reliable)
  • 堆疊狀態-你現在可以把狀態從堆疊中推進和彈出
  • UnrealScript預處理-支持宏和條件編譯
  • 調試函數-添加了新的調試函數
  • 默認屬性-defaultproperties有所改變和增強
  • 默認結構-現在結構也有默認屬性了
    • 不允許再給配置或局部變量設置缺省值
    • Defaultproperties在運行變為只讀,不允許做class'MyClass'.default.variable = 1 操作
  • 動態數組-動態數組新增了一個find()方法,用於按索引查詢元素
  • 動態數組迭代器-現在能用foreach操作動態數組的方法
  • 函數委託-現在UE3允許委託作為函數的參數
  • 接口-添加對接口的支持
  • 訪問其他類的常量:class'SomeClass'.const.SOMECONST
  • 支持多定時器
  • 函數默認參數值-現在能指定函數的可選參數了,給可選參數設定默認值即可
  • 支持工具提示(Tooltip)-當您的鼠標懸浮在屬性上時,如果那個屬性的UnrealScript上面存在/** 工具提示文本 */的註釋聲明,那麼編輯器屬性窗口將會顯示一個包含該註釋信息的工具提示。
  • 支持元數據-通過與元數據相關聯的各種屬性擴充遊戲和編輯器的功能

程序結構示例[編輯]

這一個典型、簡單的UnrealScript類的例子,它演示了UnrealScript的語法特點。請注意,此代碼可能和當前的虛幻原始碼不一致,因為這個文檔並不參與代碼同步。

//=====================================================================
// TriggerLight.
// A lightsource which can be triggered on or off.
//=====================================================================

class TriggerLight extends Light;

//---------------------------------------------------------------------
// Variables.

var() float ChangeTime; // Time light takes to change from on to off.
var() bool bInitiallyOn; // Whether it's initially on.
var() bool bDelayFullOn; // Delay then go full-on.

var ELightType InitialType; // Initial type of light.
var float InitialBrightness; // Initial brightness.
var float Alpha, Direction;
var actor Trigger;
 
//---------------------------------------------------------------------
// Engine functions.
 
// Called at start of gameplay.
function BeginPlay()
{
   // Remember initial light type and set new one.
   Disable( 'Tick' );
   InitialType = LightType;
   InitialBrightness = LightBrightness;
   if( bInitiallyOn )
   {
      Alpha = 1.0;
      Direction = 1.0;
   }
   else
   {
      LightType = LT_None;
      Alpha = 0.0;
      Direction = -1.0;
   }
}
 
// Called whenever time passes.
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;
}
 
//---------------------------------------------------------------------
// Public states.
 
// Trigger turns the light on.
state() TriggerTurnsOn
{
   function Trigger( actor Other, pawn EventInstigator )
   {
      Trigger = None;
      Direction = 1.0;
      Enable( 'Tick' );
   }
}
 
// Trigger turns the light off.
state() TriggerTurnsOff

{
   function Trigger( actor Other, pawn EventInstigator )
   {
      Trigger = None;
      Direction = -1.0;
      Enable( 'Tick' );
   }
}
 
// Trigger toggles the light.
state() TriggerToggle
{
   function Trigger( actor Other, pawn EventInstigator )
   {
      log("Toggle");
      Trigger = Other;
      Direction *= -1;
      Enable( 'Tick' );
   }
}
 
// Trigger controls the light.
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)進行訪問。沒有所謂的全局函數和全局變量。詳見
  • 變量聲明。UnrealScript支持非常多的變量類型,包括c/java的基本類型、對象引用、結構和數組。此外,變量還可聲明為讓設計人員無需進行任何編程工作,就能在UnrealEd(虛幻關卡編輯器)訪問的可編輯屬性。這些屬性使用var()語法進行聲明,而不是用var。詳見
  • 函數。函數有一個可選的參數列表和返回值。函數可以有局部變量。一些函數由虛幻引擎本身調用(比如BeginPlay)。一些函數由其他地方的腳本代碼調用(比如Trigger)。詳見
  • 代碼。支持c和java的標準關鍵字,象for、while、break、switch、if等等。花括號和分號的用法和c、c++和java中的一樣。
  • 引用元件(actor)和對象。在腳本中,你能看到一些函數,被另外一個對象通過對象引用調用的情況。詳見
  • 「state「(狀態)關鍵字。這個腳本定義了一些「state「,它由函數、變量和代碼構成,這些成分只在元件(actor)進入相應的狀態時才被執行。詳見
  • 請注意,在UnrealScript中所有關鍵字、變量名、函數和對象名是不區分大小寫的。在UnrealScript、Demo、demON和demon是相同的東西。

虛幻虛擬機[編輯]

虛幻虛擬機由以下部分組成:伺服器、客戶端、渲染引擎和引擎支持代碼。

虛幻伺服器控制玩家和元件之間的所有互動。在單人遊戲中,客戶端和服務端運行在同一台機器上;網絡遊戲的伺服器運行於一台專用機器中;所有玩家使用客戶端鏈連接到這台機器上。

所有玩家都在關卡中進行遊戲,關卡是個包含幾何體和元件的獨立環境。虛幻伺服器有同時運行多個關卡的能力。每個關卡獨立運作互相隔離:元件不能在關卡之間往來,並且一個關卡中的元件不能和另外一個關卡中的元件進行通信。

地圖中的每一個元件可以被玩家(網絡遊戲中可以有很多玩家)和腳本控制。腳本可以定義元件如何移動以及如何和其他元件交互。遊戲世界中的元件有序的運作,腳本的執行,事件的發生,等等的一切是如何在UnrealScript中實現的。你可以在下面找到答案:

在時間處理方面,虛幻將每秒的遊戲邏輯劃分為tick做單位的時間片。一個tick是活動對象(actor)被 update的最小時間間隔。在大部分情形下,一個tick 為百分一或者十分一秒tick的劃分細度是依cpu的表現性能的。cpu越強大,計算能力越強,tick就可以劃分得越細。

UnrealScript中的一些命令零tick執行(也就是說,執行它們,遊戲時間沒有任何流逝),而另一些則需要花費許多tick。需要花費遊戲時間的函數稱為「潛伏函數」。Sleep,FinishAnim,和MoveTo都是潛函數的例子。潛伏函數只能在狀態代碼(state code)中調用,不能從函數代碼中調用(包括state函數定義)。

在活動對象的潛伏函數執行完成前,它的state不會繼續執行。而它的非潛伏函數仍然可以被其他活動對象和VM調用。這樣的結果是,可以在任何時間調用UnrealScript函數,即使潛伏函數還未完成。

從傳統編程角度來看UnrealScript的行為,似乎關卡中的每個活動對象都執行在自己的線程中。實際上,在UnrealScript內部並沒有使用Windows線程,因為那樣效率過低(Window95和WindowNT無法高效的處理數以千計的線程並發)。而是採用UnrealScript模擬線程。這對UnrealScrit來說是透明得,當你用c++書寫和UnrealScript進行交互的代碼時顯得非常明顯。

所有得UnrealScript腳本是獨立執行得。如果在一個關卡中有100個怪物在周圍走動,所有這些怪物腳本對每一個tick來說是同時獨立得執行得。

筆記:有兩種時間概念:1、現實世界得時間;2、遊戲世界中得時間;現實中得時間一般是用秒來衡量的,也不存在最小時間單位這個概念,因為物理上得時間是很難把握得,我們能感覺時間得流逝,確無法準確得測量它定義它(除非理論物理得到突破,建立大統一理論)。。。。,而遊戲中得時間是由程序定義得,我們從現實中得時間簡化出了遊戲世界時間得概念,在虛幻中遊戲時間得最小單位是tick(相當於現實得10-100毫秒),為了保持遊戲對象得時間同步,UnrealScript使用了模擬線程,以保證在定義中得遊戲世界中遊戲對象時間得絕對性質(遊戲對象得狀態變化絕對獨立,每個遊戲對象得時間絕對同時流逝),這在現實中是不可能得。現實中不存在絕對時間得概念,即使通常差別不大。這並不是說幾億個cpu同時執行就能解決同時性的問題,物理本質上就不存在所謂的絕對同時,時間的絕對性是個幻覺。

對象層次結構[編輯]

[編輯]

每個腳本文件對應一個類,以class聲明為開頭,後面是類的父類和類的相關信息。簡單的例子如下:

class MyClass extends MyParentClass;

這裏聲明了一個名稱為「MyClass」的新類,這個類繼承了「MyParentClass「的所有功能。此外類駐留在名為」MyPackage「的包中。

每個類繼承父類的所有變量和函數以及狀態。每個類都可以申明新的變量和新的函數(或者重寫已經存在的函數)以及添加新的狀態(或為已有的狀態添加功能)。

在UnrealScript中設計一個新類(例如一個牛頭人怪物)的典型的做法是,從具備你需要的功能的已有類(例如,Pawn類,所有怪物的基類)繼承。

通過這樣的做法,你永遠都不用重新發明輪子--可以簡單的添加新功能,你可以在自定義的同時保持不需要定製的現有功能。這種做法特別適合從虛幻中繼承AI,內置的AI系統提供了大量的基本功能,同時你還可以建立自己的生物。

類聲明有以下可選的說明符:

Native(包名稱)(本機類)

指示:「這個類使用幕後c++支持「。虛幻native類包含在一個c++寫的exe中。只有native類可以申明native函數或實現native接口。native始終來自native類。與腳本變量和特定的函數協作,native類需要創建一個自動生成的C + +頭文件。默認情況下,包名是腳本類所在的exe名稱。例如,引擎包中的類,要求EngineClasses.h文件。

NativeReplication

表示這個類的變量複製處理在c++中實現。只能用於native類。

DependsOn(ClassName[,ClassName,....])(依賴於)

表示ClassName是在這個類前編譯。ClassName必須和這個類處於同一個包或者前一個包。可以用一個DependsOn指定多個依賴類,他們用逗號隔開。也可以使用多個DependsOn指定。

Abstract

聲明類是一個「基本的抽象類」。這可以防止這個類被無意的實例化。這個關鍵字會對其內部子類起作用,但是不會對其他腳本文件中的子類起作用。

Deprecated(過時的)

類的所有對象被加載但不保存。當關卡設計師在關卡設計器中載入包含過時活動對象被的地圖時,他們會收到編輯器的警告信息。這個關鍵字會對其子類產生作用。

Transient(瞬態)

表示該類的對象不應該被保存在磁盤上,這和一些非持久性的本機類自然結合是有用的。比如播放器和窗口。這個關鍵字會對其子類起作用;子類能使用NotTransient關鍵字重寫它。

NotTransient(非瞬態)

表示不從基類繼承Transient關鍵字標註的瞬態特性。

Config(IniName)(配置)

表明這個類允許訪問ini文件中的數據。如果在類中有可配置變量(使用config和globalconfig申明),這可以讓類訪問那些保存在指定的配置文件的變量。這個標誌將被傳播到所有子類並且不能被否定,但是子類可以通過config關鍵字指定不同的配置文件。通常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:類的每個對象的配置信息都會被保存在配置文件中。每個對象在配置文件中都有一個如下格式的配置節[ObjectName ClassName]。這個關鍵字會對其子類起作用。

PerObjectLocalized

類得本地化數據將被定義在每對象得基礎上。每個對象在已命名得本地化文件中有個如下格式得節[ObjectName ClassName]。這個關鍵字會對其子類起作用。

EditInlineNew

編輯器,表示這個類的對象能從虛幻便捷器的屬性窗口創建(默認行為是可以通過關聯的屬性窗口引用已經存在的對象)。這個關鍵字會對其子類起作用。子類可以使用NotEditInlineNew關鍵字重寫它。

NotEditInlineNew

編輯器,不從基類繼承EditInlineNew關鍵字。如果沒有任何父類使用EditInlineNew關鍵字將不起效果。

Placeable(可放置)

編輯器。表示這個類可以通過虛幻編輯器放到關卡,UI場景,或者kismet窗口(由類的類型定)。這個標誌將被傳播到其所有子類中;子類能通過NotPlaceable關鍵字重寫它。

NotPlaceable

編輯器。不從基類繼承NotPlaceable關鍵字。表示這個類不能在虛幻編輯器中放入關卡。

HideDropDown

編輯器。防止這個類在虛幻編輯器的屬性窗口的組合框中顯示。

HideCategories(Category[,Gategory,......])

編輯器。表示這個類的對象在虛幻編輯器的屬性窗口中隱藏一個或多個類別。使用無類別聲明可以隱藏變量,使用類名稱聲明變量的名稱。

ShowCategories(Category[,Category,......])

編輯器。不從基類繼承ShowCategories關鍵字。

AutoExpandCategories(Category[,Category,......])

編輯器。指示一個或多個類別在編輯器的屬性窗口中自動展開。使用無類別聲明可以自動展開變量,使用類名稱聲明變量的名稱。

Collapsecategories

編輯器。表示類的屬性不應該在虛幻編輯器的屬性窗口類別中被分組。這個關鍵字會對其子類起作用;子類可以用DontCollapsecategories關鍵字重寫它。

DontCollapsecategories

編輯器。表示不從基類繼承Collapsecategories。

Within ClassName

高級。表示類的對象離不開ClassName的實例。為了建立這個類的對象,您必須指定作為外部對象ClassName的實例。這個關鍵字必須作為class申明的後的第一關鍵字。

Inherits(ClassName[,ClassName,......])

高級,使用多繼承。只是適用於native類。不支持從多個UObject類繼承。

Implements(ClassName[,ClassName,......])(實現)

高級。指示類實現的多個接口。只有nataive類可以實現native接口。

NoExport

高級。表明這個類的c++聲明不應該通過腳本編譯器包含在自動生成c++頭文件中。類的c++聲明手動定義在一個單獨的頭文件中。只適用於native類。

變量[編輯]

變量類型[編輯]

內置類型 (Built-in types)[編輯]

這裏有一些在 UnrealScript 中宣告變數的例子:


var int a; // 宣告一個名稱為"A"的整數變數。

var byte Table[64]; // 宣告一個長度64的靜態 1-byte 陣列。

var string PlayerName; // 宣告一個名稱為"PlayerName"的字串變數。

var actor Other; // 實體化 Actor 類別,並命名為"Other"。

var() float MaxTargetDist; // 宣告一個名稱為"MaxTargetDist"的浮點數變數,並且它的值可以從 UnrealEd 的屬性窗口中修改。


變數在 UnrealScript 能出現在兩種地方:實體變數,它可以在整個類別內使用,在宣告完類別或 struct 後立即出現。局部變數,出現在函數中,只有在函數執行時有效。實體變數使用關鍵字 var 宣告。局部變數用關鍵字 local 宣告,例如:


function int Foo()

{

  local int Count;
  Count = 1;
  return Count;

}


以下是 UnrealScript 中支持的內置變數類型:


byte: 1-byte 值,範圍從 0 到 255。

int: 32-bit 整數值。

bool: 布林運算值: 不是 true 就是 false。

float: 32-bit 浮點數值。

string: 一個字串(see Unreal Strings)。

constant: 不能修改的變數。

enumeration: 一個能夠代表多個預先設定的整數值中的其中一個值。例如:在 Actor 內定義為 enumeration 的變數 ELightType 描述了一個動態光源,它的值可以像 LT_None、LT_Pulse、LT_Strobe,等等...。

聚合類型(Aggregate data types)[編輯]

虛幻類型[編輯]

變量說明符(specifiers)[編輯]

變量可編輯機制(Editability)[編輯]

數組[編輯]

結構[編輯]

結構說明符(specifiers)[編輯]

枚舉[編輯]

常量[編輯]

對象和元件(actor)引用變量[編輯]

類引用變量[編輯]

表達式[編輯]

賦值[編輯]

類之間轉換對象引用[編輯]

函數[編輯]

函數聲明[編輯]

函數參數說明符(specifiers)[編輯]

函數重載(Function Overriding)[編輯]

"函數重載"是指在子類別中寫一個同名的新函數。例如:你正在為一個名叫 Demon 的新怪物寫一個類別。這個 Demon 類別,是繼承自 Pawn 類別。現在,當怪物重生第一次看到玩家時,會呼叫父類別 Pawn 的 SeePlayer 函數,所以這個怪物會開始攻擊這個玩家。這是一個很好的概念,但是當你想在你的新的 Demon 類別中以不同的方式處理 SeePlayer 函數時,你該怎麼實現?答案就是函數重載。

重載一個函數,只需要從父類別中將函數的定剪下並複製貼上到你的新類別中。例如:你可以加入SeePlayer 函數到你的新類別 Demo 中。


// New Demon class version of the Touch function.

function SeePlayer( actor SeenPlayer )

{

  log( "The demon saw a player" );
  // Add new custom functionality here...

}

函數重載是創造新 UnrealScript 類別的關鍵。你可以創造一個繼承自現有類別的新類別。然後,你需要做的事是重載一個你需要進行不同做法的函數。這可以使你在不必寫大量程式碼的情況下就建造一個新的類別。

在 UnrealScript 中的某些函數以 final 關鍵字做定義。這個 final 關鍵字(在關鍵字 function 馬上出現的修飾字)意思是"這個函數無法被子類別所重載"。這可以用在一個你知道沒有人會去重載的函數中,因為它會有更快的代碼執行速度。例如:假如你有一個稱做 VectorSize 用來計算一個向量大小的函數。可以確定的是絕對沒有任何原因來讓任何人重載它,所以可以在 function 後馬上加入關鍵字 final。另一方面,像 Touch 這類的函數是很注重情境的,所以不能宣告它為 final。

函數高級說明符(specifiers)[編輯]

控制結構[編輯]

循環結構[編輯]

For循環[編輯]

Do循環[編輯]

While循環[編輯]

Continue語句[編輯]

Break語句[編輯]

分支結構[編輯]

If-Then-Else語句[編輯]

Case語句[編輯]

Goto語句[編輯]

語言功能[編輯]

內置運算符及其優先級[編輯]

一般功能[編輯]

創建對象[編輯]

整數函數[編輯]

浮點功能[編輯]

字符串函數[編輯]

向量函數[編輯]

定時器函數[編輯]

調試函數[編輯]

UnrealScript預處理[編輯]

UnrealScript工具和實用程序[編輯]

腳本探測[編輯]

腳本調試器[編輯]

語言高級特性[編輯]

定時器[編輯]

狀態[編輯]

狀態概述[編輯]

狀態標籤和潛伏函數[編輯]

狀態繼承和作用域法則[編輯]

高級狀態規劃[編輯]

堆疊狀態[編輯]

複製[編輯]

迭代語句(Foreach)[編輯]

函數調用說明符[編輯]

在可變類中訪問靜態函數[編輯]

變量的默認值[編輯]

通過類引用訪問變量的默認值[編輯]

使用defaultproperties塊指定默認值[編輯]

語法[編輯]

默認結構[編輯]

動態數組[編輯]

長度變量[編輯]

迭代動態數組[編輯]

接口類[編輯]

函數委託[編輯]

Native類[編輯]

元數據支持[編輯]

元數據概述[編輯]

使用多個元數據規範[編輯]

可用的元數據規範[編輯]

高級技術問題[編輯]

UnrealScript實施[編輯]

UnrealScript二進制兼容性問題[編輯]

技術說明[編輯]

UnrealScript編程策略[編輯]

參考資料[編輯]