UnrealScript语言基础
总体特征
(1)大小写不敏感。关键字、宏、变量名、函数名以及类名不区分大小写;变量名可以与关键字同名
(2)局部变量、成员变量未初始化时,会被编译器初始化
(3)没有全局变量、全局函数,所有东西必须写入类中
(4)一个uc文件中,有且只能写一个类,且文件名与类名要一致
(5)变量和函数默认为public类型,函数默认为虚函数
(6)不支持函数重载,但支持运算符重载和缺省参数
(7)不支持异常处理,不支持模板泛型
(8)无需显示导入外部包,uc文件可以使用当前包及之前编译的包中定义的类型和函数
(9)没有构造函数,没有析构函数,通过引用计数机制进行垃圾回收
(10)没有指针类型;数值型、bool型、名称、字符串、枚举、数组、结构体为值类型;类、接口为引用类型
(11)只支持一维数组
(12)没有静态变量,没有union类型
(13)所有对象都从Object类单根继承,支持接口多继承
(14)强类型,编译时检查
(15)解释执行,运行时安全
预处理
编译命令参数
make -intermediate // 编译脚本,并将预处理结果保存到 UDKGame\PreProcessedFiles\<package>\<class>.uc
make -debug // 定义名为debug的宏变量,启用`logd宏函数,并编译脚本
make -final_release // 定义名为final_release的宏,禁用`log、`logd、`warn、`assert宏函数,并编译脚本
make -nopreprocess // 不进行预处理(关闭宏及注释的预处理)
注:
`log(string OutputString, optional bool bRequiredCondition, optional name LogTag);
`logd(string OutputString, optional bool bRequiredCondition, optional name LogTag);
`warn(string OutputString, optional bool bRequiredCondition);
`assert(bool bCondition);
作用范围
1. 宏的作用范围是在文件内,意味着当前文件中的 X 行上的宏变量只能在该文件的 X+n 行中使用
2. 为了能让工程中多个文件使用宏变量,一般是将宏变量定义在.uci文件中(如:TGDefine.uci),然后各个文件的起始处`include(TGDefine.uci)
3. 定义在工程的根目录下的Globals.uci文件中的宏,能直接被这个包和依赖该包的包使用
注:脚本编译程序不能监测出uci文件的修改,因此修改uci文件后可以同时修改某个uc文件以触发所在包的编译;或者全量编译脚本
条件编译
`if(`notdefined(USE_ASYNCHRONOUS_MOVE)) // ... `endif `if(`isdefined(USE_ASYNCHRONOUS_MOVE)) // ... `else // ... `endif `if(`isdefined(USE_ASYNCHRONOUS_MOVE)) // ... `else `if(`isdefined(USE_COMMAND)) // ... `else // ... `endif
宏定义、宏取消
`define USE_ASYNCHRONOUS_MOVE `define WEAPON_CONFIG config // `WEAPON_CONFIG 另外可以加上花括号,确保宏周围的空白是有效的 如:var `{WEAPON_CONFIG} bool m_bConfigTest; `define GRAPH_INCOSIZE 8 `define LOCATION "(" $ Name $ ") `{ClassName}::" $ GetStateName() $ ":" $ GetFuncName() `define MAX(a, b) ( ((`a)<(`b))?(`b):(`a) ) `define ShowVar(expr,name) "`if(`name) `name `else `expr `endif:'" $ `expr $ "'" // ShowVar换行写法如下 `define ShowVar(expr,name) "\ `if(`name)\ `name\ `else\ `expr\ `endif\ :'" $ `expr $ "'" `define LogWarn(cat, msg) `log("WARN:" @ `msg,,`cat) // 定义一个代理对象数组 `define DefineDelegateVariable(CallbackName) var private array<delegate<On`{CallbackName}> > On`{CallbackName}Delegates; // 增加一个代理对象到数组中 `define DefineAddDelegateHandlers(CallbackName) \ function Add`{CallbackName}Delegate(delegate<On`{CallbackName}> CallBack) \ { \ if (On`{CallbackName}Delegates.Find(Callback) == INDEX_None) \ { \ On`{CallbackName}Delegates[On`{CallbackName}Delegates.Length] = Callback; \ } \ } // 从数组中删除指定的代理对象 `define DefineRemoveDelegateHandlers(CallbackName) \ function Clear`{CallbackName}Delegate(delegate<On`{CallbackName}> Callback) \ { \ local int RemoveIndex; \ RemoveIndex = On`{CallbackName}Delegates.Find(Callback); \ if (RemoveIndex != INDEX_None) \ { \ On`{CallbackName}Delegates.Remove(RemoveIndex, 1); \ } \ } // 取消宏定义 `undefine(INCLUDE_GAME_STATS)
文件包含
`include(TGOnlineLogicMacros.uci)
引擎定义的宏
`{Data} // 当前日期 `{Time} // 当前时间 `{GameName} // 游戏名称 `{ClassName} // 当前类名 `{PackageName} // 当前包名
特殊宏
`define MyMacro(p1, p2, p3, p4) “This macro contains `# parameters.”// `#为4,为宏参数的个数
常量
作用范围
1. 常量在运行时不可改变,可以定义在类中、成员函数内、状态块内,但编译器会将其统一调整到类中;好的编码习惯是将常量定义在类的起始处。
2. 定义在结构体中的常量将只能在结构体中使用,外部无法访问。
3. 当前类中定义的常量可直接访问:PI;访问外部类TGTest中定义的常量:class'TGTest'.const.PI 注:TGTest类的工程编译需在使用该常量的工程之前或同处一个工程
4. 对于公共常量,一般会将这些常量集中写入到一个单独的.uci文件中(如:TGConst.uci),然后类的起始处`include(TGConst.uci)
举例
const a = 10; // 十进制 a=10 const b = 0x10; // 十六进制 转成十进制为:b=16 const c = 010x; // 八进制 转成十进制为:c=8 const d = true; const f = 3.14; const s = "Hello World!"; // 字符串需加上双引号 const n = 'James'; // name需加上单引号 const o = none; // 空对象 相当于C/C++中的NULL const oc = class'UTGame.UTPawn'; // 类模板(引号中不能有空格) class<UTPawn> const oc2 = class'UTBot'; // 类模板(引号中不能有空格) class<UTBot> const or = Texture2D'EngineResources.DefaultTexture';//纹理对象(引号中不能有空格) const v = vect (1.2, 3.4 , 5.6); // vector常量 const r = rot(1234, 5678 , 9012); // rotator常量
Object类中的常量
const MaxInt = 0x7fffffff; const Pi = 3.1415926535897932; const RadToDeg = 57.295779513082321600; // 180 / Pi const DegToRad = 0.017453292519943296; // Pi / 180 const UnrRotToRad = 0.00009587379924285; // Pi / 32768 const RadToUnrRot = 10430.3783504704527; // 32768 / Pi const DegToUnrRot = 182.0444; const UnrRotToDeg = 0.00549316540360483; const INDEX_NONE = -1; // Aspect ratio constants const AspectRatio4x3 = 1.33333; const AspectRatio5x4 = 1.25; const AspectRatio16x9 = 1.77778; const InvAspectRatio4x3 = 0.75; const InvAspectRatio5x4 = 0.8; const InvAspectRatio16x9 = 0.56249;
变量
更多类型说明请参见:https://wiki.beyondunreal.com/Types
unreal texture:http://www.unrealtexture.com/Unreal/Downloads/3DEditing/UnrealEd/Tutorials/unrealwiki-offline/variable-type.html
unrealscript DefaultProperties:中文 en
数值型
类型 | 长度 | 范围 | 举例 |
byte |
8位无符号整型 | [0, 255] |
十进制:2 八进制:012x 十六进制:0xFF |
int | 32位整型 | [-2^31, 2^31-1] |
十进制:-500 八进制:018000x 十六进制:0x12FC |
float | 32位浮点(单精度) |
[-3.403e+38, 3.403e+38] 有效精度:6-7位有效数字 |
-3.25 5.0f 0.35 10. .58(不支持省略0的写法,编译失败) 1.23E2(不支持科学计数法,编译失败) 1.0/0.0=1.#INF00(比任何浮点数都大) -1.0/0.0=-1.#INF00(比任何浮点数都小) |
数值型间转换规则
1. 自动隐式转换
2. 精度高向精度低转换:
(a) 内存截断 (b) 精度丢失
类的缺省变量
simulated function float GetRange(Pawn P) { if (default.LifeSpan == 0.0)//访问当前类的缺省变量LifeSpan { return 15000.0; } if (P.Default.JumpZ > 1000)//访问对象P所在类的缺省变量JumpZ { return 20000.0; } if (class'Pawn'.Default.MaxStepHeight > 100)//访问Pawn类的缺省变量MaxStepHeight { return 25000.0; } return 10000.0; }
>>>补零右移运算符
local int a, b; a = -1; // 0xFFFF FFFF b = a>>2; // b=0xFFFF FFFF=-1 b = a>>>2; // b=0x3FFF FFFF=1073741823
float ~= 约等于符号
local float f; local bool b; f = 0.00001; b = (f~=0); // b=true 等价于 abs(f)<0.0001
float ** 幂函数符号
local float f1, f2, f3; f1 = 3.0; f2 = 2.0; f3 = f1**f2;//f3=9 3的2次幂
float极大值、极小值 、NaN
local bool b1; local float f1, f2; f2 = 0.0; f1 = 1.0 / f2; // 1.#INF00 b1 = IsNan(f1);//false b1 = (f1==f1);//true if (f1 > 1000000000)//true { `log("f1为极大值"); } if (f1 < -1000000000)//false { `log("f1为极小值"); } f1 = -1.0 / f2;// -1.#INF00 b1 = IsNan(f1);//false b1 = (f1==f1);//true if (f1 > 1000000000)//false { `log("f1为极大值"); } if (f1 < -1000000000)//true { `log("f1为极小值"); } f1 = f2/f2;//-1.#IND00 b1 = IsNan(f1);//true b1 = (f1==f1);//false f1 = -f2/f2;//-1.#IND00 b1 = IsNan(f1);//true b1 = (f1==f1);//false
bool
(1)bool型只能为True或False
(2)bool型与数值型间不支持隐式转换
local int a; local bool b; a = 10; b = a; // 编译错误 b = bool(a); // b=true a = b; // 编译错误 a = int(b); // a=1
(3)^^ 异或
local bool b1, b2, b3; b1 = true; b2 = false; b3 = b1^^b2; // b3=true b1 = true; b2 = true; b3 = b1^^b2; // b3=false
name
(1)name字符:“a..z”、“A...Z”、"0...9"、“_”、“-”、空格,最大允许长度为1023字符
如: 'Nico Chen' '123' '' '#逆战@123' name ("#逆战@123")
(2)name不区分大小写 'nico' 和 'Nico'是相等的
(3)name在函数中用单引号包含,defaultproperties块中无需包含或使用双引号包含
defaultproperties { m_name1='Hello'//Warning, Invalid property value m_name1='' m_name2=Hello_123//m_name2='Hello_123' m_name3=Hello World//m_name3='Hello' m_name4=Hello#World//m_name4='Hello' m_name5="Hello World!"//m_name5='Hello World!' m_name5=Hello// Warning, redundant data m_name5仍然为'Hello World!' }
(4)通过NameOf()伪函数在编译时,将变量名和函数名转换成name
(5)name只能强制转换成string,不能转换成其他类型;同时string可以强制转换成name
(6)可以修改name,但无法修改name的内容
(7)name只支持两种比较运算符:==、!=
string
(1)string中的字符为16位unicode,最大允许长度为1023字符
如: "NicoChen" "Hello World!\n" "" "逆战"
(2)string区分大小写 "nico"和 "Nico"是不相等的
(3)可以修改string,但无法修改string的内容
(4)string在函数中用双引号包含,defaultproperties块中无需包含或使用双引号包含
defaultproperties { m_string1='Hello'//Warning, Invalid property value m_string1="" m_string2=Hello_123//Warning, Missing " m_string2="Hello_123" m_string3=Hello World//Warning, Missing " m_string3="Hello" m_string4=Hello#World//Warning, Missing " m_string4="Hello#World" m_string5="Hello World!"//m_string5='Hello World!' m_string5=Hello// Warning, redundant data m_string5仍然为'Hello World!' }
(5)除了数组与结构体外,其他类型都可强制转成string
local string s; // 其他类型转成字符串 s = string(''); // s="" s = string('James'); // s="James" s = string(50); // s="50" s = string(-1234); // s="-1234" s = string(-13.89); // 保留6位有效数字 s="-13.8900" s = string(true); // s="True" s = string(false); // s="False" s = string(ENetRole.ROLE_Authority); //s="3" s = string(GetEnum(Enum'ENetRole', ENetRole.ROLE_Authority)); //s="ROLE_Authority" s = string(self); //代码位于MyPawn类中,s="MyPawn_1" s = string(none); //s="None"
(6)string可强制转成数值型、bool和name
local name m; local bool b; local byte n; local int a; local float f; // 字符串转成name m = name("test"); // m='test' m = name("Hello World!"); // m='Hello World!' // 字符串:整型 b = bool("-1"); // b=true a = int("-1"); // a=-1 n = byte("-1"); // n=255 f = float("-1");// f=-1.000000 // 字符串:浮点数 b = bool("-300.23"); // b=true a = int("-300.23"); // a=-300 n = byte("-300.23"); // n=byte(-300)=212 f = float("-300.23");// f=-300.230011 // 字符串:布尔值 b = bool("True"); // b=true a = int("True"); // a=0 n = byte("True"); // n=0 f = float("True");// f=0.000000 // 字符串:起始为数字子串 b = bool("210fAlse300"); // b=true a = int("210fAlse300"); // a=210 n = byte("210fAlse300"); // n=210 f = float("210fAlse300"); // f=210.000000 // 字符串:起始不为数字子串 b = bool("True335Test"); // b=false a = int("True335Test"); // a=0 n = byte("True335Test"); // n=0 f = float("True335Test"); // f=0.000000
(7)string支持所有的比较运算符 >、>=、<、<=、==、!=、~=
(8)string特有连接运算符 @ $ @= $= 注:@ 、$会将其左右操作数执行coerce转换成string类型;@= 、$=会将右操作数执行coerce转换成string类型
(9)string特有运算符 -= 注:-=会将右操作数执行coerce转换成string类型;a -= b等价于a = Repl(a, b, "", false)
local bool b1; local string s1; // string操作符 s1 = "Hello"$"World"; // "HelloWorld" s1 = "Hello"@"World"; // "Hello World" s1 = "Hello"; s1 $= "World"; // "HelloWorld" s1 = "Hello"; s1 @= "World"; // "Hello World" //s1 = "Hello"+"World"; // 编译错误 //s1 += "World"; // 编译错误 s1 = "Hello WOrld"; s1 -= "o"; // 去掉子串中所有的小写字母o(大小写敏感) s1="Hell WOrld" b1 = "Hello"<"World"; // 大写字母<小写字母 b1=true b1 = "Hello">"hello"; // 大写字母<小写字母 b1=false b1 = "Hello"!="hello"; // 大小写敏感 b1=true b1 = "Hello"~="hello"; // 大小写敏感 b1=true b1 = "Hello"=="Hello"; // b1=true b1 = "Hello"<="Hello"; // b1=true b1 = "Hello">="Hello"; // b1=true b1 = "Hello"!="Hello"; // b1=false b1 = "Hello"~="Hello"; // b1=true
(10)string函数
local int a1; local array<string> v1, v2, v3, v4; local string s1; // Object函数 a1 = Len("Hello"); // a1=5 a1 = Instr("THIS is my book!", "is"); // 返回第1个is的位置(大小写敏感) a1=5 s1 = Mid("Hello", 0, 2); // 返回从0索引开始后2个长度的子串 s1="He" s1 = Mid("Hello", 2); // 返回从2索引开始到结尾长度的子串 s1="llo"; s1 = Left("World", 2); // s1="Wo" s1 = Right("Hello", 4); // s1="ello" s1 = Caps("Hello"); // 返回字符串的大写版本 s1="HELLO" s1 = Locs("World"); // 返回字符串的大写版本 s1="world" s1 = Chr(97); // 返回给定int的字符串表示形式(可以是Unicode:0-65535内的任何值)s1="a" a1 = Asc("Hello"); // 返回字符串第一个字母的Unicode数值 a1=72 // 将"This is a test"中的"is"替换成"was" 大小写不敏感 s1="THwas was a test" s1 = Repl("THIS is a test", "is", "was"); // 将"Two be or not two be"中的"two"替换成"to" 大小写敏感 s1="Two be or not to be" s1 = Repl("Two be or not two be", "two", "to", true); // 将"Two be or not two be"中的"two"替换成"to" 大小写不敏感 s1="to be or not to be" s1 = Repl("Two be or not two be", "two", "to", false); // 返回从第1次出现"is"(大小写敏感)到结尾的子串(含is) s1="is is a test" s1 = Split("This is a test", "is", false); // 返回从第1次出现"is"(大小写敏感)到结尾的子串(不含is) s1="a test" s1 = Split("THIS is a test", "is", true); // 返回"Test_45_50_me20"最右边"_"后的子串 s1="me20" s1 = GetRightMost("Test_45_50_me20"); v1[0] = "Hello "; v1[1] = ""; v1[2] = "World"; // 使用#连接数值v1中的各个元素(空串不跳过) s1="Hello ##World" JoinArray(v1, s1, "#", false); // 使用#连接数值v1中的各个元素(空串跳过) s1="Hello #World" JoinArray(v1, s1, "#", true); // 使用"M"分隔字符串(大小写敏感),并将结果保存到数组v2中(空串不跳过) ParseStringIntoArray("HelloMMmWorld", v2, "M", false);//v2[0]="Hello" v2[1]="" v2[2]="mWorld" // 使用"M"分隔字符串(大小写敏感),并将结果返回到数组v2中(空串不跳过) v2 = SplitString("HelloMMmWorld", "M", false); //v2[0]="Hello" v2[1]="" v2[2]="mWorld" // 使用"M"分隔字符串(大小写敏感),并将结果保存到参数数组v2中(空串跳过) ParseStringIntoArray("HelloMMmWorld", v3, "M", true);//v3[0]="Hello" v3[1]="mWorld" // 使用"M"分隔字符串(大小写敏感),并将结果返回到数组v2中(空串跳过) v3 = SplitString("HelloMMmWorld", "M", true); //v3[0]="Hello" v3[1]="mWorld" // Actor函数 s1 = "This is a test"; // 等价于:s1=Repl(s1, "is", "was", true); 将字符串中的"is"替换成"was" 大小写敏感 s1为输出参数 ReplaceText(s1, "is", "was"); // 返回s1="Thwas was a test" s1 = "Two be or not two be"; // 等价于:s1=Repl(s1, "two", "to", true); 将字符串中的"two"替换成"to" 大小写敏感 s1为输出参数 ReplaceText(s1, "two", "to"); // 返回s1="Two be or not to be" // 等价于:v4=SplitString("www.qq.com", ".", true);s1=v4[v4.Length-1]; s1="com" s1 = GetItemName("www.qq.com");
enum
(1)枚举只能在类中定义,不能在函数中定义 如:ENetRole
// Net variables. enum ENetRole { ROLE_None, // No role at all. ROLE_SimulatedProxy, // Locally simulated proxy of this actor. ROLE_AutonomousProxy, // Locally autonomous proxy of this actor. ROLE_Authority, // Authoritative control over the actor. }; var enum ENetMode { NM_Standalone, // Standalone game. NM_DedicatedServer, // Dedicated server, no local client. NM_ListenServer, // Listen server. NM_Client // Client only, no local server. } NetMode;
(2)枚举第一个元素的值为0,后续依次+1;不能随意地指定新的起始值
(3)enum内部为一个byte类型,其支持最大的枚举值为255
(4)在defaultproperties中对枚举成员变量初始化时,不能带枚举类型前缀,否则会失效
(5)枚举类型(等于枚举元素的个数)、类型.前缀_MAX、类型.EnumCount及类型.枚举元素(一定要带上类型)可作为静态数组的大小
local int a1[ENetRole]; // 等价于a1[4] local int a2[ENetRole.EnumCount]; // 等价于a2[4] local int a3[ENetRole.ROLE_MAX]; // 前缀_MAX 等价于a3[4] local int a4[ENetRole.ROLE_Authority]; // 等价于a4[3]
(6)整型与enum之间支持隐式转换
local byte a; local ENetRole nr; nr = 3; // nr=ROLE_Authority nr = -1; // nr=INVALIDE nr = 10; // nr=INVALIDE a = ENetRole.ROLE_SimulatedProxy; // a=1
(7)使用GetEnum函数将enum转换成name
local name m; m = GetEnum(Enum'ENetRole', ENetRole.ROLE_Authority); // m='ROLE_Authority'
(8)枚举定义所在工程编译需在使用该枚举的工程之前或【同处一个工程且使用该枚举所在类名按字母升序比枚举定义所在类名靠后】
如果一个枚举在当前工程中广泛地使用,需要打破类名按字母升序的限制,可以将该枚举定义在一个单独从Object派生的类中(如:TGType)
若使用该枚举所在的类名按字母升序较靠前,可以使用dependson(TGType)来解决编译找到类型问题
(9)枚举类型定义采取的是覆盖规则:若包加载序列为:ABC,A中定义了枚举类型EType,B中也定义了该类型,则C包中则会使用B中定义的枚举类型
静态数组
(1)不支持size为1的静态数组定义 local int a[1];
(2)不支持bool型静态数组定义 local bool b[5];
(3)不支持多维静态数组 local int a[2][2];
(4)无法修改静态数组的值,但可以修改静态数组的内容 如:b=a; // 编译错误
(5)越界访问情况,不会导致崩溃
local int a[5]; a[6] = 8; // a[4]=8 a[-1] = 2; // a[0]=2 a[1] = a[-1]; // a[1]=2
(6)通过ArrayCount()伪函数在编译时,得到静态数组大小
(7)静态数组元素访问在函数中用[],defaultproperties块中用()或[]均可
var int m_sa1[5]; defaultproperties { m_sa1(-1)=2 // m_sa1(0)仍然为0 m_sa1(0)=3 // m_sa1(0)=3 m_sa1(3)=1 m_sa1(3)=5 // Warning, redundant data m_sa1(3)仍然为1 m_sa1(6)=8 // Warning, Out of bound array m_sa1(4)仍然为0 }
(8)静态数组作为函数参数
simulated function Test() { local int xx[3]; StaticArrayTest(xx); } function StaticArrayTest(int a[3]) { a[0] = 5; a[1] = 12; a[2] = 20; }
(9)静态数组不能作为函数返回值
动态数组
(1)可以定义bool类型的动态数组
(2)动态数组既可以作为函数参数,也可以作为函数返回值
(3)避免写>>,否则编译不过 local Array<class<Actor>>; local Array<delegate<OnFailed>>
(4)不支持动态数组嵌套 local Array<Array<int> > vva;
(5)既可以修改动态数组的值,又可以修改动态数组的内容
(6)函数中通过Length字段,获取动态数组size(defaultproperties块中不能访问Length)
(7)函数中修改Length字段,调整动态数组size
local array<int> va; va.Length = 5; // va size=5: 0 0 0 0 0 va.Length = 0; // va size=0 va.Length = va.Length+3; // va size=3: 0 0 0 va.Length = -1; // va size=-1 //va.Length += 1; // 编译出错 不能对Length进行+=运算 //va.Length -= 1; // 编译出错 不能对Length进行-=运算 //va.Length++; // 编译出错 不能对Length进行后自增运算 //va.Length--; // 编译出错 不能对Length进行后自减运算 //--va.Length; // 编译出错 不能对Length进行前自减运算 //++va.Length; // 编译出错 不能对Length进行前自增运算 // function ChangeArrayLength(out int x){x=10;} //ChangeArrayLength(va.Length); // ChangeArrayLength中修改va.Length,会导致内存泄露和崩溃
(8)动态数组元素访问在函数中用[],defaultproperties块中用()或[]均可
(9)函数中使用索引修改元素的值时,若索引>=Length,将引发动态数组size增长
local array<int> va; local array<color> vb; local color c; va[2] = 10; // va size=3: 0 0 10 va[-1] = 5; // 无效语句 va size=3: 0 0 10 va[1] = 3; // va size=3: 0 3 10 va[2] = va[5]+8; // va size=3: 0 3 8 vb[1].R = 255; // vb size=0 注:不会引发size增长 c.G = 128; vb[2] = c; // vb size=3 [r=0 g=0 b=0 a=0] [r=0 g=0 b=0 a=0] [r=0 g=128 b=0 a=0]
(10)动态数组在defaultproperties中初始化
var Array<int> m_da1, m_da2; defaultproperties { m_da1[0]=2 // m_da1:2 m_da1(-1)=3 // Warning, Invalid property value m_da1:2 m_da1(1)=5 // m_da1:2 5 m_da1(1)=10 // Warning, redundant data m_da1:2 5 m_da1(3)=7 // m_da1:2 5 0 7 m_da2(4) = 10 //m_da2: 0 0 0 0 10 m_da2 = (1,,3) //m_da2: 1 0 3 m_da2 = () // Warning, redundant data m_da2: 1 0 3 m_da2(1) = 5 // m_da2: 1 5 3 m_da2(4) = 8 // Warning, redundant data m_da2: 1 5 3 }
(11)函数中清空动态数组
va.Length = 0;
(12)defaultproperties中清空动态数组
defaultproperties
{
m_da1.Empty
}
(13)使用函数来修改动态数组size,追加、删除、插入元素到动态数组中
local array<int> va; va.AddItem(1); // 末尾增加值为1的元素 size=1 a: 1 va.Add(3); // 末尾扩充3个元素 size=4 a: 1 0 0 0 va.Insert(2, 2); // 在索引为2处插入2个元素 size=6 a: 1 0 0 0 0 0 va.Remove(1, 3); // 从索引为1处起删除3个元素 size=3 a: 1 0 0 va.AddItem(5); // 末尾增加值为5的元素 size=4 a: 1 0 0 5 va.RemoveItem(0); // 删除所有为0的元素 size=2 a: 1 5 va.InsertItem(1, 7); // 在索引为1处插入值为7的元素 size=3 a: 1 7 5
(14)defaultproperties中使用函数来追加、删除元素
var Array<int> m_da1; defaultproperties { m_da1.Add(1) // 末尾增加元素为1的元素 size=1 m_da1: 1 m_da1.Add(2) // 末尾增加元素为2的元素 size=2 m_da1: 1 2 m_da1.Add(5) // 末尾增加元素为5的元素 size=3 m_da1: 1 2 5 m_da1.Add(2) // 末尾增加元素为2的元素 size=4 m_da1: 1 2 5 2 m_da1.Remove(5) // 删除所有值为5的元素 size=3 m_da1: 1 2 2 m_da1.RemoveIndex(1) // 删除索引值为1的元素 size=2 m_da1: 1 2 }
(15)元素查找
local int n; local Rotator r; local Object o1, o2; local array<int> va; local array<Rotator> vr; local array<Object> vo; va[0]=1; va[1]=2; va[2]=6; va[3]=2; n = va.Find(2); // n=1 第1个为2的元素的索引值为1 n = va.Find(3); // n=INDEX_NONE(即:-1) 未找到为3的元素 r.Pitch=1000; r.Roll=2000; r.Yaw=3000; vr.AddItem(r); r.Pitch=4000; r.Roll=5000; r.Yaw=6000; vr.AddItem(r); n = vr.Find('Pitch', 4000); // n=1 第1个Pitch=4000的元素的索引值为1 n = vr.Find('Roll', 500); // n=-1 未找到Roll=500的元素 n = vr.Find('Yaw', 3000); // n=0 第1个Yaw=3000的元素的索引值为0 o1 = new(self) class'ObjectEx'; vo.AddItem(o1); o2 = new(self) class'ObjectEx'; vo.AddItem(o2); n = vo.Find(o2); // n=1 第1个为o2的元素的索引值为1
(16)元素排序
// 返回值<0,则交换a和b;否则不交换 delegate int IntSortAscDelegate(int a, int b) { if (a <= b) // 等于情况,一定不要交换,否则会死循环 return 0; // 不进行交换 return -1; // 进行交换 } simulated function DynamicArrayTest5() { local array<int> va; va[0] = 8; va[1] = 6; va[2] = 0; va[3] = 5; va[4] = 9; va[5] = 3; va[6] = 2; va[7] = 6; va.Sort(IntSortAscDelegate); // va: 0 2 3 5 6 6 8 9 }
(17)元素遍历
local int i, n, s1, s2, s3; local array<int> va; va[0] = 8; va[1] = 6; va[2] = 0; va[3] = 5; va[4] = 9; va[5] = 3; va[6] = 2; va[7] = 6; foreach va(n, i) { s1 += i; // s1=0+1+2+3+4+5+6+7=28 } foreach va(n) { s2 += n; // s2=8+6+0+5+9+3+2+6=39 } for(i=0; i<va.Length; i++) { s3 += va[i]; // s3=8+6+0+5+9+3+2+6=39 }
(18)静态数组与动态数组拷贝比较
local int i; local int a[3], ac[3]; local Array<int> va, vac; a[0] = 2; a[1] = 5; // a: 2 5 // ac = a; // 编译失败,静态数组不能通过赋值方式拷贝 // 循环拷贝静态数组a中的值到ac中 for (i=0; i<ArrayCount(a); i++) { ac[i] = a[i]; } va.AddItem(2); va.AddItem(5); vac = va; // 拷贝动态数组 vac: 2 5
struct
(1)结构体中可以存放常量和任意类型变量(小心避免直接或间接包含自身类型的变量,会引起编译崩溃 如下:)
struct STRTest { var STRTest c; };
(2)结构体中不能有函数方法,成员的初始化放在structdefaultproperties块中
(3)结构体只能在类中定义
struct Student { var string sname; var int age; var float height; var byte scores[3]; var Array<int> history; var Color clr; structdefaultproperties // 初始化变量的默认值 { sname = "James" age = 20 height = 1.83 scores(0)=87.5 scores(1)=96.5 history=(95,100,88) clr= (r=255,g=32,b=128,a=0) } };
(4)支持结构体继承
// A point or direction vector in 3d space. struct immutable Vector { var() float X, Y, Z; }; // A plane definition in 3d space. struct immutable Plane extends Vector { var() float W; };
(5)函数中对进行结构体赋值和拷贝
local Student s1, s2; s1.sname = "Tom"; s1.age = 30; s1.height = 1.90; s1.clr.r = 255; s2 = s1; // 结构体赋值 s2.sname = "Jack"; // 结构体为值类型 s1.sname仍然为"Tom"
(6)在类的defaultproperties块中对结构体成员变量进行初始化
var Student m_student1, m_student2; defaultproperties { m_student1 = (sname="Lucy",age=8,height=1.77, clr=(r=200,b=150)) m_student2 = {( sname="Lily", age=10, height=1.68, clr=(r=200,b=150), scores[0]=80,scores[1]=90,scores[2]=85, history=(100,120,150,180,200) )} }
(7)支持==与!=比较(两个结构体内容完全一致则相等,否则不相等)
(8)结构体定义所在工程编译需在使用该结构体的工程之前或【同处一个工程且使用该结构体所在类名按字母升序比结构体定义所在类名靠后】
如果一个结构体在当前工程中广泛地使用,需要打破类名按字母升序的限制,可以将该结构体定义在一个单独从Object派生的类中(如:TGType)
若使用该结构体所在的类名按字母升序较靠前,可以使用dependson(TGType)来解决编译找到类型问题
(9)结构体类型定义采取的是覆盖规则:若包加载序列为:ABC,A中定义了结构体类型FlyInfo,B中也定义了该类型,则C包中则会使用B中定义的结构体类型
修饰符
关键字 |
说明 |
immutable |
使用c++来进行二进制序列化,可以减少空间占用和提升性能 在这样的结构体中增删成员变量会引发序列化问题 struct immutable Vector |
immutablewhencooked | 在使用cook包时,启用immutable特性 |
native |
native结构体,会导出到.h中 struct native KeyBind /** if true, the bind will not be activated if the corresponding key is held down */ structcpptext |
{XXX} |
在导出的c++中类型名为XXX struct {QWORD} qword // qword在c++中类型为QWORD struct {WxRect} ViewportDimension // ViewportDimension在c++中类型为WxRect struct {FNavMeshEdgeBase*} EdgePointer // EdgePointer在c++中类型为FNavMeshEdgeBase* |
注1:结构体其他修饰符请参考后文中类修饰符对应关键字
注2:结构体成员的修饰符请参考后文中类成员修饰符对应关键字
结构体更多信息请参见:
常用结构体 -- vector
运算符
(1)向量与向量 加减乘 + - * += -= *=
local vector v1, v2, v3; v1.x = 1.0; v1.y = 2.0; v1.z = 3.0; v2.x = 1.0; v2.y = 5.0; v2.z = 2.0; v3 = v1 + v2; // v3.x=2.0 v3.y=7.0 v3.z=5.0 v3 = v1 - v2; // v3.x=0.0 v3.y=-3.0 v3.z=1.0 v3 = v1 * v2; // v3.x=1.0 v3.y=10.0 v3.z=6.0 //v3 = v1 / v2; // 编译失败 没有除法 v3 = v1; v3 += v2; // v3.x=2.0 v3.y=7.0 v3.z=5.0 v3 = v1; v3 -= v2; // v3.x=0.0 v3.y=-3.0 v3.z=1.0 v3 = v1; v3 *= v2; // v3.x=1.0 v3.y=10.0 v3.z=6.0 //v3 = v1; v3 /= v2; // 编译失败 没有除法
(2)向量比较运算符 == !=
(3)- 负号运算符
local vector v1, v2; v1.x = 1.0; v1.y = 2.0; v1.z = 3.0; v2 = -v1; // v2.x=-1.0 v2.y=-2.0 v2.z=-3.0
(4)缩放
local vector v1, v2; v1.x = 1.0; v1.y = 2.0; v1.z = 3.0; v2 = 2.0*v1; // v2.x=2.0 v2.y=4.0 v2.z=6.0 v2 = v1*2.0; // v2.x=2.0 v2.y=4.0 v2.z=6.0 v2 *= 2.0; // v2.x=4.0 v2.y=8.0 v2.z=12.0 v2 /= 2.0; // v2.x=2.0 v2.y=4.0 v2.z=6.0 v2 = v1/2.0; // v2.x=0.5 v2.y=1.0 v2.z=1.5
(5)dot 点乘
local vector v1, v2, v3; local int n; v1.x = 1.0; v1.y = 2.0; v1.z = 3.0; v2.x = 0.0; v2.y = 5.0; v2.z = 2.0; n = v1 dot v2; // n=v1.x*v2.x+v1.y+v2.y+v1.z*v2.z=16.0
(6)cross 叉乘
local vector v1, v2, v3; v1.x = 1.0; v1.y = 2.0; v1.z = 3.0; v2.x = 0.0; v2.y = 5.0; v2.z = 2.0; v3 = v1 cross v2; // v3.x=v1.y*v2.z-v1.z*v2.y= -11.0 // v3.y=v1.z*v2.x-v1.x*v2.z= -2.0 // v3.x=v1.x*v2.y-v1.y*v2.x= 5.0
(7)旋转 << >>
local vector v1, v2; local rotator r1; v1.y = 1.0; r1.yaw = 65536/4; // 方位角 0-360分担到0-65536上 90 左手坐标系 v2 = v1 >> r1; // 正向旋转 v2.x=-1.0 v2 = v1 << r1; // 反向旋转 v2.x=1.0
(8)与string进行类型转换
local vector v; local string s; v = vect(1.23456,2.12,3.5688);//v=(1.234560,2.120000,3.568800) s = string(v);//s="1.23,2.12,3.57" 四舍五入,保留小数点后两位 s = "-3.7856235,,20,15.688"; v = vector(s);//v=(-3.785624,0.000000,20.000000)//按逗号进行分割,每个子块按照string转float规则进行转换
函数
(1)长度 VSize(v) VSize2D(v)
(2)长度的平方 VSizeSq(v) VSizeSq2D(v)
(3)单位化 Normal(v)
(4)随机向量 v=VRand()
(5)是否为0向量 IsZero(v)
(6)忽略z的点乘 NoZDot(v1, v2)
常用结构体 -- rotator
pitch (think nodding to say "yes") 俯仰角 绕-y轴 -->可通过下列公式:(65536+pitch%65536)%65536归一化到[0,65535]
yaw(shaking your head to say "no") 方位角 绕+z轴 -->可通过下列公式:(65536+yaw%65536)%65536归一化到[0,65535]
roll (tilting your head sideways while looking in a specific direction) 横滚角 绕-x轴 -->可通过下列公式:(65536+roll%65536)%65536归一化到[0,65535]
范围: [0,360)-> [0, 65536) 公式:y = 360.0*x/65536 注:y为度数,x为pitch、yaw或roll
(1)与string进行类型转换
local rotator r; local string s; r.Pitch = 65536/16;//r1 [Pitch=4096 yaw=0 roll=0] r.yaw = 65536/8;//r1 [Pitch=4096 yaw=16384 roll=0] s = string(r);//s="4096,16384,0" s = "-21.36,70000,65535,100"; r = rotator(s);//[Pitch=-21 yaw=70000 roll=65535] //按逗号进行分割,每个字块按照string转int规则进行转换
(2)运算符
a. rotator与rotator加减 + - += -=
b. rotator比较运算符 == !=
c. 缩放
(3)函数
a. 长度 RSize(r)
b. 求夹角(单位:度 范围:[0, 180]) RDiff(r1, r2)
控制语句
(1)循环语句
local int i, n, s; local array<int> va; local Controller C; for (i=0; i<=100; ++i) // i<=100 条件为false时,退出循环 { s += i; } //for (i=0,s=0; i<=100; ++i,s+=2) // i=0,s=0 和 ++i,s+=2编译不过,脚本不支持逗号表达式 //{ //} i = 0; s = 0; while (i<=100) // i<=100 条件为false时,退出循环 { s += i; i++; } i = 0; s = 0; do { s += i; i++; } until(i>100);// i>100 条件为true时,退出循环 // foreach 数组 va[0] = 2; va[1] = 5; va[2] = 3; va[3] = 6; va[4] = 9; i = 0; s = 0; foreach va(n, i) { s += i; // s=0+1+2+3+4=10 } s = 0; foreach va(n) { s += n; // s=2+5+3+6+9=25 } // foreach 迭代器函数 //native final iterator function AllControllers(class<Controller> BaseClass, out Controller C); 注:第2个参数C必须为第1个参数指定的类型,不能为其基类或派生类 foreach WorldInfo.AllControllers(class'Controller', C) { }
(2)goto语句
// 函数中使用goto语句 goto labelname; function GotoTest() { Label1: local name n; local int s; n = 'Label1'; if (s >= 2) { //goto ('Label3'); // 编译出错 goto 'Label3'; } s = 1; Label2: s = 2; //goto (Label1); // 编译出错 //goto (n); // 编译出错 函数中goto的Label不能使用变量 goto Label1; Label3: s = 3; //goto Unknown; // 编译出错 函数中找不到名为Unknown的标签 } // 状态中使用goto语句 goto expression; state State1 { function name SelectLabel(int Index) { switch (Index) { case 1: return 'Label1'; case 2: return 'Label2'; case 3: return 'Label3'; } return 'Unknown'; } Begin:// State默认进入的Label goto SelectLabel(2); Label1: goto ( SelectLabel(3) ); Label2: LabelName = SelectLabel(1); // LabelName为成员变量 goto LabelName; Label3: //goto Unknown; // 编译不过 goto 'Unknown'; // 未定义Label,后续的代码将被忽略 LabelName = 'State1'; // 不会得到执行 }
a. foreach循环中的使用goto只允许跳转到当前foreach作用范围的Lable上,不能跳转到内部嵌套的foreach循环或者foreach外部的Label上;
也就是说每个foreach的作用范围都是独立的黑盒(Lable对外不可见),只能在其内部使用goto,不能跨层使用。
b. 其他循环类型及条件语句的作用范围为整个函数,没有这样的限制
类
① 动态地加载某个类模板,并创建出一个实例
local class<actor> NewClass; NewClass = class<actor>( DynamicLoadObject( "UTGameContent.UTVehicle_Hoverboard_Content", class'Class' ) ); if( NewClass!=None ) { Spawn( NewClass,,,Vect(100,0,0) ); }
注:当包未打开时,首先会调用LoadPackage打开该包;该物体有指向外部包的引用时,若外部包未打开,则调用LoadPackage打开外部包并用DynamicLoadObject来加载引用指向的物体(这是一个递归过程)
② 在c++中,通过Cast模板函数进行类型转换
APawn* Instigator; // 若Instigator不为空且为一个ATGPawn实例,则转换成功,否则返回空 ATGPawn* tPawn = Cast<ATGPawn>(Instigator);
缺省属性
var class<GameReplicationInfo> GameReplicationInfoClass; var class<LocalMessage> DeathMessageClass; var TGComDamageZone BodyDamageZoneTemplate; var ParticleSystem MuzzleFlashPSCTemplate; var const LightComponent LightComponent; var instanced ParticleSystemComponent PoweredUpEffect; defaultproperties { GameReplicationInfoClass=class'UTGame.UTGameReplicationInfo'//类型与当前类不在同一个包时,必须带上包名前缀 DeathMessageClass=class'UTDeathMessage' //类型与当前类在同一个包时,可省略包名前缀 // 从Actor生成出来的Archetype资源 被引擎管理 当前类被加载时,BodyDamageZoneTemplate指向的资源也会被加载到内存 BodyDamageZoneTemplate=TGComDamageZone'WP_LinkGun.DamageZone.TGComDamageZone_Body' //MuzzleFlashPSCTemplate指向的资源为模板类型 被引擎管理 当前类被加载时,MuzzleFlashPSCTemplate指向的资源也会被加载到内存 //当前类被卸载时,MuzzleFlashPSCTemplate指向的资源的引用会-1,当该资源没任何对象引用时,会被GC自动回收 //由于native包会常驻内存,因此要避免在native包中直接引用资源 MuzzleFlashPSCTemplate=ParticleSystem'WP_LinkGun.Effects.P_FX_LinkGun_3P_Primary_MF' // 创建一个类型为DominantPointLightComponent DominantPointLightComponent0对象,并赋值给成员变量LightComponent // 由当前类管理,所有当前类创建出来实例都指向同一份DominantPointLightComponent0的内存 Begin Object Class=DominantPointLightComponent Name=DominantPointLightComponent0 LightAffectsClassification=LAC_DYNAMIC_AND_STATIC_AFFECTING CastShadows=TRUE CastStaticShadows=TRUE CastDynamicShadows=TRUE bForceDynamicLight=FALSE UseDirectLightMap=FALSE bAllowPreShadow=TRUE LightingChannels=(BSP=TRUE,Static=TRUE,Dynamic=TRUE,bInitialized=TRUE) PreviewLightRadius=DrawLightRadius0 PreviewLightSourceRadius=DrawLightSourceRadius0 End Object Components.Remove(PointLightComponent0) //将基类中的PointLightComponent0对象从Components数组中删除 LightComponent=DominantPointLightComponent0 //将LightComponent指向创建的DominantPointLightComponent0对象 Components.Add(DominantPointLightComponent0) //将DominantPointLightComponent0对象添加到Components数组中 // 会为当前类型创建一个SkeletalMeshComponent0对象 // 由当前类管理,所有当前类创建出来实例都指向同一份SkeletalMeshComponent0的内存 // 改写基类中SkeletalMeshComponent0对象的属性 Begin Object Name=SkeletalMeshComponent0 SkeletalMesh=SkeletalMesh'WP_LinkGun.Mesh.SK_WP_LinkGun_3P' Translation=(Z=1) Rotation=(Roll=-400) Scale=0.9 End Object // 创建一个类型为ParticleSystemComponent PoweredUpComponent对象,并赋值给成员变量PoweredUpEffect // 由当前类管理,所有当前类创建出来实例都指向同一份SkeletalMeshComponent0的内存 Begin Object Class=ParticleSystemComponent Name=PoweredUpComponent Template=ParticleSystem'WP_LinkGun.Effects.P_WP_Linkgun_PoweredUp' bAutoActivate=false SecondsBeforeInactive=1.0f End Object PoweredUpEffect=PoweredUpComponent // PoweredUpEffect被instanced修饰,为实例变量,在进行赋值时会产生ParticleSystemComponent类型拷贝 }
类修饰符
关键字 | 说明 |
extends |
继承某个类 class Actor extends Object |
implements(IAAA,IBBB,...) |
继承1个或多个接口 |
Inherits(CAAA,CBBB,...) |
用于native类,继承1个或多个类 |
within XXX |
Within修饰符指出这个类的实例仅可以在XXX类的实例的内部进行创建,且必须将当前XXX类的实例作为这个类实例的Outer class AICmd_AD14Hades_Skill_Birth extends AICommand 注:在类中可以直接访问调用XXX的变量和函数 |
abstract | 抽象类 不能用该类型创建实例 |
native native(XXX) |
native类 native:生成的.h文件名为:当前包名+Classes.h、当前包名+Names.h native(XXX):生成的.h文件名为:当前包名+XXXClasses.h、当前包名+XXXNames.h |
config(XXX) |
指定类的配置文件为DefaultXXX.ini 子类可以重新指定对应的配置文件YYY(DefaultYYY.ini),若没有指定则往上搜寻其最近父类的config来确定其所在的配置文件名称 |
PerObjectConfig |
类的每个实例各自存储在ini特定的tab块中 [TheWorld:PersistentLevel.TPlayerController_0.TPlayerInput_0 TPlayerInput] |
noexport |
与native一起使用 使得这个类的native声明排除在自动生成的C++头文件之外。当使用这个修饰符时,必须在单独的头文件中手动地创建native类声明 |
dependson(CAAA,CBBB,...) | 告诉uc编译器在编译当前类之前,先编译CAAA,CBBB,... |
transient |
该关键字会被子类继承 使得类不能保存到磁盘 |
nontransient | 去除从父类继承过来的transient特性 |
editinlinenew |
该关键字会被子类继承 EditInlineNew修饰符声明了这个类可以有一个从编辑器的属性窗口中直接创建的新的实例。 |
noneditinlinenew |
去除从父类继承过来的editinlinenew特性 |
placeable |
该关键字会被子类继承 可以把类放置到编辑器中的关卡、UIScene或Kismet中 注1:加粗的类型为placeable,选中一个类型后可以在关卡中右键菜单选择Add XXX Here将该类型的一个实例添加到关卡 注2:Volume类型需要通过右边工具栏上的Add Volume图标进行添加 |
NotPlaceable |
去除从父类继承过来的placeable特性 |
HideDropDown |
使得类不会显示在编辑器的该类的类型下拉列表中 |
hidecategories(AAA,BBB,...) |
该关键字会被子类继承 在属性框中隐藏名为AAA,BBB,...的Tab页内容,使得属性框免于混乱,妨碍设计人员查看属性。 |
showcategories(AAA,BBB,...) |
和hideCategories关键字完全相反的效果,它会使得父类中已经使用HideCategories修饰符隐藏的特定种类显示出来。 |
AutoExpandCategories(AAA,BBB,...) |
查看属性时默认地完全展开AAA,BBB,...的Tab页内容 |
CollapseCategories |
该关键字会被子类继承 查看属性框内容时,去掉标签分类,所有的可编辑变量都会按照字母顺序排列为单独的一列。 |
DontCollapseCategories |
去除从父类继承过来的CollapseCategories特性 |
NativeReplication |
仅在native类中有用,意味着属于类中放置在replication块中变量是通过c++代码来处理 需要重写virtual INT* GetOptimizedRepList(BYTE* Recent, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, UActorChannel* Channel)函数 |
udn MasteringUnrealScriptClasses:中文 英文
成员变量修饰符
关键字 | 说明 |
private | 私有成员变量,仅能被当前类中的访问(uc脚本中) |
protected | 保护成员变量,仅能在当前类和子类中访问(uc脚本中) |
privatewrite | 在当前类中可写,其他地方只能读(uc脚本中) |
protectedwrite | 在当前类和子类中可写,其他地方只能读(uc脚本中) |
private{private} |
第1个private指明uc脚本中的访问权限,第2个private导出到c++中访问权限 var private{private} transient int LODLevel; |
const |
常量,不能在uc脚本中修改(但可在cpp中修改) 如:var(Movement) const vector Location; |
editconst |
var() native const editconst name Name;// 在uc脚本中不可修改,在编辑器属性框中不可编辑 var(Collision) editconst PrimitiveComponent CollisionComponent;// 在编辑器属性框中不可编辑 |
() (XXX) |
可以在编辑器属性框中看到该变量 ():该变量会被分类到当前类名的Tab下 (XXX):该变量会被分类到名为XXX的Tab下 |
native |
通过C++而非uc脚本来初始化和保存 var native const editconst class Class; |
noexport |
该变量不会包含在自动生成的类声明中 |
pointer pointer(Type)
|
一个指向object或Type类型的指针 在uc中的定义如下: struct pointer var native private const editconst pointer HashNext; // 生成c++:UObject* HashNext; var const transient native Pointer CachedFloatProperty{UFloatProperty}; // 生成c++:UFloatProperty* CachedFloatProperty; |
<> |
在变量上指定元数据以提供额外信息,以供引擎或编辑器使用,从而提供扩展功能。 请参考:unrealscript元数据 属性窗口 var( Attenuation ) float RadiusMin<ToolTip=The range at which the sound starts attenuating>; // 为RadiusMin变量提供Tips信息,在编辑器中把鼠标放在属性框该字段上会显示该Tips var (LightEnvironment) float CharacterLitIndirectBrightness <UIMin=0.1 | UIMax=1.0 | ClampMin=0.0 | ClampMax=5.0>; // CharacterLitIndirectBrightness变量:UI条上最小值为0.1,最大值为1.0;该变量最小值为0.0,最大值为5.0 |
export |
对Object类型的成员变量有效。当对象被复制(复制/粘帖)或导出到T3D中时,不是仅仅输出对象引用本身,而是将该成员所指向的对象作为一个子对象块整体地导出。 |
noimport |
与export相反:导入T3D文本时,将跳过这个变量。 换句话说,当导入或者 复制/粘帖 对象时,这个变量的值将不会被传递到新的对象实例中。 |
editinline |
允许在属性框中编辑这个变量所引用的物体属性。。该变量只能为对象类型或对象数组类型 如ParticleSystemComponent.uc中: var() editinline array<ParticleSysParam> InstanceParameters; |
editoronly |
仅在运行编辑器时会被加载,在游戏中该变量将被丢弃。 |
instanced |
仅用于对象属性。 当创建当前类的实例时,将用类的默认属性中定义的对象产生一个副本,并赋值给该变量。 |
init |
用于在native类中声明的字符串和动态数组 被作为FString或TArray(而不是FStringNoInit 或TArrayNoInit)导出到头文件中。'Init'属性不能被赋予默认值,因为当创建对象时,默认值将会被清除。 var init array<byte> VisibilityFactors;
struct native Category structcpptext |
localized |
使用本地化文件中配置文本 语言设置在DefaultEngine.ini的[Engine.Engine]的Language字段(如:INT、CHT等) // UTPlayerReplicationInfo.uc在UTGame包中 class UTPlayerReplicationInfo extends PlayerReplicationInfo; var localized string OrdersString[8];
在Localization\INT\UTGame.int中 [UTPlayerReplicationInfo] |
config |
这个变量在ini中配置,不能在默认属性中设置,调用SaveConfig会将当前值保存会ini文件 详细参见udn:中文 英文 class GameInfo extends Info var config string DefaultGameType; struct native GameTypePrefix var config array<GameTypePrefix> DefaultMapPrefixes;
在Config\DefaultGame.ini中配置 [Engine.GameInfo] DefaultGameType="UTGame.UTDeathmatch" +DefaultMapPrefixes=(Prefix="DM",bUsesCommonPackage=FALSE,GameType="UTGame.UTDeathmatch") +DefaultMapPrefixes=(Prefix="CTF",bUsesCommonPackage=TRUE,GameType="UTGameContent.UTCTFGame_Content");bUsesCommonPackage=TRUE 没有重复项 添加配置成功
注1:config成员变量所在的配置文件由当前类的config(XXX)来指定,若当前类没指定,则往上搜寻其最近父类的config(XXX)来确定其所在的配置文件名称 注2:若DefaultMapPrefixes数组在子类中没有被重新配置,则直接使用父类配置;若DefaultMapPrefixes数组在子类中被配置,则会使用当前配置(丢弃父类DefaultMapPrefixes数组配置) 注3:config变量在运行过程中被修改后,可以通过调用SaveConfig()来保存实例的config变量到T开头的配置文件中,调用StaticSaveConfig()来保存类的default缺省对象的config变量到T开头的配置文件中 local TGame tGame; tGame = TGame(WorldInfo.Game); tGame.ConfigVar = 1500; 最后在生成出来的TGame.ini中,ConfigVar为1500 [UTGame.TGame] ConfigVar=1500 |
globalconfig |
这个变量在ini中配置,不能在默认属性中设置;与config相比,globalconfig不允许派生的子类重新配置该变量(配置了没有用,始终读取当前类的配置数值) class UTGame extends UDKGame var globalconfig float EndTimeDelay;
在Config\DefaultGame.ini中配置 [UTGame.UTGame] EndTimeDelay=4.0 GameSpecificMapCycles=(GameClassName="UTDeathmatch",Maps=("DM-Sanctuary","DM-Deck","DM-Gateway"));添加第一个数组元素 |
transient |
这个变量是临时使用的,且不是对象永久状态的一部分。Transient变量不会被保存到磁盘。当加载一个对象时,Transient变量被初始化为类的默认值。 var transient bool bNetDirty; |
duplicatetransient |
当创建对象的副本时,该变量的值将被重置为类的默认值。 |
repnotify |
若该变量被放置在replication块中,则该变量会在ReplicatedEvent事件函数中收到回调通知 var repnotify int PlayLoopEffectRepIdx; replication simulated event ReplicatedEvent(Name VarName) |
input |
在Unreal的输入系统中是可以访问的该变量,从而使输入(比如按钮的押下和操作杆的运动)能够和变量直接地进行映射。该变量只能为byte或float类型
如Controller.uc中: // Input buttons. 在Bindings中使用bFire变量 Bindings=(Name="Fire",Command="Button bFire | StartFire | OnRelease StopFire") |
interp |
该变量可以受到Matinee中的浮点或向量属性轨迹的驱动从而随时间改变 如CameraActor.uc中: var() interp float AspectRatio; var() interp float FOVAngle; |
deprecated |
该变量在不久的将来将会被删除,该字段可以被加载,但不能被保存。 |
NonTransactional |
在编辑器中修改该变量不能被Undo或Redo |
databinding |
某个UI控件可以SetDatastorebinding和该变量进行绑定,使得该变量变化时,UI会进行刷新 var databinding int GoalScore;
Lbl = UILabel(FindChild('ServerRules',true)); |
unreal texture variable syntax
成员函数
无论是成员函数还是静态成员函数,都是虚函数,可以被子类重写
class UTWeaponAttachment extends Actor;
{
static function string FuncTest()
{
return "Hello";
}
}
class TGWeaponAttachment extends UTWeaponAttachment;
{
static function string FuncTest()
{
return "Good";
}
}
local string Text;
local class<UTWeaponAttachment> AttachmentClass;
AttachmentClass = class'TGWeaponAttachment';
Text = AttachmentClass.static.FuncTest(); //Text="Good"
调用缺省全局状态函数:Global.StopFiring();
调用直接父类函数:Super.PostBeginPlay();
调用继承树某个父类函数:Super(UTWeapon).FireAmmunition();
函数空实现:simulated function vector Test(); // 编译器会自动添加返回各成员为0的vector代码
关键字 | 说明 |
private | 私有函数,仅能被当前类中的访问 |
protected | 保护函数,仅能在当前类和子类中访问 |
public | 公共函数,能在所有类中访问 |
simulated |
带该关键字的函数:不仅能被ROLE_AutonomousProxy、ROLE_Authority对象执行,还能被Role=ROLE_SimulatedProxy对象执行 不带该关键字的函数:仅能被ROLE_AutonomousProxy、ROLE_Authority对象执行 |
final |
非虚函数,不允许被子类重写 final native function SetNetUpdateTime(float NewUpdateTime); |
native |
使用C++实现(当前类必须是native的,这也意味着当前脚本包为native包) native function float GetGravityZ(); native(266) final function bool Move( vector Delta ); // native后的圆括号内的数字和在C++中GNatives数组中idx是相对应的 导出的.h文件中生成float GetGravityZ()的定义以及粘合函数execGetGravityZ的实现 另外,开发者必须在某个cpp中实现float GetGravityZ() |
noexport |
与native一起使用,不应该导出这个native函数的C++函数定义,仅导出该函数的在脚本粘合版本的定义。 native final function noexport SetHardAttach(optional bool bNewHardAttach); 在导出的.h文件中不生成void SetHardAttach(optional bool bNewHardAttach)函数,仅仅导出粘合函数execSetHardAttach的定义 另外,开发者必须在cpp中实现void SetHardAttach(optional bool bNewHardAttach)和execSetHardAttach
noexport一般与cpptext块配合使用: cpptext virtual void SetHardAttach(UBOOL bNewHardAttach); } cpptext会使得导出的.h文件中生成virtual void SetHardAttach(UBOOL bNewHardAttach)函数的定义 然后,开发者在cpp中实现virtual void SetHardAttach(optional bool bNewHardAttach)和execSetHardAttach 在execSetHardAttach中,添加SetHardAttach函数调用,将脚本和cpp的调用关系连接起来 这种方式可以使得uc、cpp的函数(是否为virtual,函数名,参数顺序或个数可以不一样)相互独立开 |
const |
与native一起使用,使得导出的c++函数定义也是带有const,不允许在函数内修改成员变量 native final function GetComponentsBoundingBox(out box ActorBox) const; 导出的.h文件中生成void GetComponentsBoundingBox(FBox& ActorBox) const; |
iterator |
与native一起使用,在导出的.h文件中仅仅导出粘合函数execDynamicActors的定义 另外,开发者必须在cpp中实现execDynamicActors 在uc脚本中可以使用foreach调用该函数 local Pawn P; |
static |
类缺省对象函数,也是虚函数 另外,与native一起用时,该关键字会忽略,会导出成员函数,而不是静态成员函数 |
event |
替换function,生成脚本的C++调用函数,实现C++调用脚本的功能 如:脚本event Destroyed()会.h中生成void eventDestroyed()的实现 simulated event SetInitialState() |
latent |
延迟函数(只能在state的label块中调用) native(256) final latent function Sleep( float Seconds ); |
client | 被server调用的远程函数,调用后立即返回,无返回值 |
server | 被ROLE_AutonomousProxy客户端调用的远程函数,调用后立即返回,无返回值 |
reliable |
修饰client和server远程函数调用:可靠发送,保证按照顺序到达 |
unreliable | 修饰client和server远程函数调用:不可靠发送,不能保证会以任何特定的顺序到达,如果没有足够的带宽它可能会丢弃 |
exec | 控制台命令函数,仅能在某些特定的类中:UIInteraction、UISceneClient、GameViewportClient、GameInfo、PlayerInput、PlayerController、Player、Pawn、InventoryManager、Weapon、HUD、CheatManager |
Operator, PreOperator, PostOperator |
native(129) static final preoperator bool ! ( bool A ); // local bool bTest = !bTest2; |
singular |
阻止函数对其本身进行递归调用,防止出现死循环。 规则是: 如果某个actor实例已经在一个singular函数中(通过调用栈回溯查找),任何对该actor实例的后续其他singular的调用都将会被跳过。 // ************************ UTPlayerController类 ************************ singular function Test1() Test2(); //Test3(); // 编译不过 Error, Calling a singular function within a singular function on the same object will always fail UTPawn(Pawn).Func1(); function Test2() singular function Test3() // ************************ UTPawn类 ************************
UTPlayerController(Controller).Test3(); // 运行时跳过 执行ExecTest命令后,打印出: Test1! |
函数参数修饰符
关键字 |
说明 |
coerce | 自动进行类型转换 |
out | 使用引用传入值类型变量,输出型参数 |
const | 常量参数,函数中不允许改变参数 |
optional |
可选参数,必须放到函数参数列表的最右边,传参的时候不填表示使用缺省参数 native noexport final function coerce actor Spawn 调用示例:Spawn(class'CoverReplicator'); Spawn(class'DebugCameraHUD', self); Spawn(class'DynamicCameraActor', self,,,,, TRUE); Spawn(PlayerControllerClass,,, SpawnLocation, SpawnRotation); |
函数更多信息请参见:
迭代器
① 在uc脚本中迭代器需要与foreach配合来一起使用
local Actor A; local Controller C; foreach AllActors( class 'Actor', A ) { } foreach WorldInfo.AllControllers(class'Controller',C) { }
注1:在非Actor类的函数中使用Actor迭代器时,则须通过某个actor的实例来调用
注2:在非Actor类的函数中使用worldinfo迭代器时,则须通过class'WorldInfo'.static.GetWorldInfo()来调用
② 在c++中可以通过一下方式遍历不同类型的对象
// 遍历游戏世界中所有的Object for (FObjectIterator It; It; ++It) {} // 遍历游戏世界中所有的Actor for(FActorIterator ActorIt;ActorIt;++ActorIt) {} // 遍历游戏世界中所有会进行网络同步的Actor for( FNetRelevantActorIterator It; It; ++It ) {} // 遍历游戏世界中所有bStatic=false的Actor for (FDynamicActorIterator It; It; ++It) {} // 遍历游戏世界中所有开启Tick的Actor for (FTickableActorIterator It; It; ++It) {} // 遍历游戏世界中所有的UObject对象 for( TObjectIterator<UObject> It ; It ; ++It ) // 遍历游戏世界中所有的UGuidCache对象 for (TObjectIterator<UGuidCache> It; It; ++It) {} // 遍历游戏世界中所有的UParticleSystemComponent组件 for (TObjectIterator<UParticleSystemComponent> It;It;++It) {} // 遍历游戏世界中所有的ULevel对象 for( TObjectIterator<ULevel> It; It; ++It ) {} // 遍历游戏世界中所有的UPackage对象 for( TObjectIterator<UPackage> It; It; ++It ) {} // 遍历游戏世界中所有的UTexture2D对象 for (TObjectIterator<UTexture2D> It; It; ++It) {} // 遍历UEngine* GEngine中所有的LocalPlayer对象 for (FLocalPlayerIterator It(GEngine); It; ++It) {} // 遍历当前对象的Class类型所有float类型成员变量 for (TFieldIterator<UFloatProperty> It(GetClass()); It; ++It) {} // 遍历当前对象的Class类型所有结构体类型成员变量 for (TFieldIterator<UStructProperty> It(GetClass()); It; ++It) {} // 遍历所有Class类型 for( TObjectIterator<UClass> It ; It ; ++It ) {}
Actor的迭代器成员函数
//循环处理关卡中的类型为BaseClass的所有actors。如果您指定了可选参数InterfaceClass,那么则仅包含实现了InterfaceClass接口的actors。 AllActors ( class<actor> BaseClass, out actor Actor, optional class InterfaceClass ) //循环处理关卡中的bStatic=false 类型为BaseClass的所有actors。 DynamicActors( class<actor> BaseClass, out actor Actor, optional class InterfaceClass ) //循环处理当前actor具有的类型为BaseClass的所有actors。 ChildActors( class<actor> BaseClass, out actor Actor ) //循环处理以当前actor作为基类的类型为BaseClass的所有actors。 BasedActors( class<actor> BaseClass, out actor Actor ) //循环处理和当前actor相接触(渗入)的类型为BaseClass的所有actors。 TouchingActors( class<actor> BaseClass, out actor Actor ) //循环处理从 Start 点到 End 点之间使用盒式碰撞范围 Extent 进行线性跟踪所触及的类型为BaseClass的所有actors。 //在每次迭代中, HitLoc 设置为碰撞位置, HitNorm 设置为一个向外指的碰撞法线。 TraceActors( class<actor> BaseClass, out actor Actor, out vector HitLoc, out vector HitNorm, vector End, optional vector Start, optional vector Extent ) //循环处理位置Loc处的指定 Radius(半径) 内的类型为BaseClass的所有actors(若没有指定特定位置,则使用当前actor的位置)。 OverlappingActors( class<actor> BaseClass, out actor Actor, float Radius, optional vector Loc, optional bool bIgnoreHidden ) //循环处理Loc位置处可见的类型为BaseClass的所有actors(如果没有指定位置,则使用当前actor的位置)。 VisibleActors( class<actor> BaseClass, out actor Actor, optional float Radius, optional vector Loc ) //返回从位置Loc处(若没有指定特定位置,则使用当前actor的位置)指定Radius(半径)内碰撞到bCollideActors==true 类型为BaseClass的所有可见actors。该函数使用了Hash表,所以它要比 AllActors() 快很多。 VisibleCollidingActors ( class<actor> BaseClass, out actor Actor, float Radius, optional vector Loc, optional bool bIgnoreHidden ) //返回从位置Loc处(若没有指定特定位置,则使用当前actor的位置)指定Radius(半径)内碰撞到bCollideActors==true 类型为BaseClass的所有actors。该函数使用了Hash表,所以它要比 AllActors() 快很多。 CollidingActors ( class<actor> BaseClass, out actor Actor, float Radius, optional vector Loc ) //返回当前actor中包含的类型为BaseClass的所有actor组件。 ComponentList( class<ActorComponent> BaseClass, out ActorComponent out_Component ) //返回“直接或间接”附加到当前actor上类型为BaseClass的所有组件。 AllOwnedComponents( class<Component> BaseClass, out ActorComponent OutComponent ) //返回类型为BaseClass的所有本地PlayerControllers。 LocalPlayerControllers( class<PlayerController> BaseClass, out PlayerController PC)
WorldInfo的迭代器成员函数
//迭代关卡中当前具有的所有Controllers (Player 或 AI) 。 AllControllers(class<Controller> BaseClass, out Controller C) //迭代关卡中的类型为BaseClass的所有 Pawns 。可以选择性地指定迭代某个给定位置(TestLocation)周围的某个半径(TestRadius)内的 Pawns 。 AllPawns(class<Pawn> BaseClass, out Pawn P, optional vector TestLocation, optional float TestRadius) //迭代关卡中的类型为BaseClass的所有 NavigationPoint。 AllNavigationPoints(class<NavigationPoint> BaseClass, out NavigationPoint N) //迭代关卡中的类型为BaseClass的所有 NavigationPoint。可以选择性地指定迭代某个给定位置(Point)周围的某个半径(Radius)内的 NavigationPoints。 RadiusNavigationPoints(class<NavigationPoint> BaseClass, out NavigationPoint N, vector Point, float Radius) //迭代关卡中所有网络连接玩家对象的列表,同时传回了IP及端口。仅在服务器上运行。 AllClientConnections(out Player ClientConnection, out int ClientIP, out int ClientPort)
代理
接口
声明形式如下:
interface UIDataStoreSubscriber
DependsOn(UIRoot)
native(UIPrivate);
native function SetDataStoreBinding( string MarkupText, optional int BindingIndex=INDEX_NONE );
① 接口中只能有函数声明不能有函数体,派生该接口的类必须声明接口中所有函数。除native关键字外,类中的函数声明必须和接口中的声明相匹配(接口中的native函数在其派生类中不必声明为native)
② 接口允许所有的函数类型:正常的函数及事件。
③ 接口中只可以定义代理
④ 接口仅能包含不影响类的内存布局的声明 – 可以声明枚举值、结构体和常量,但是不能声明变量。
⑤ 接口可以选择扩展另一个接口。
⑥ 接口体也可以包含cpptext块(cpptext块中的函数可以有函数体),它将会同native接口声明一同被导出。
接口IXXX的成员变量PawnOwner在c++中为:TScriptInterface<class IXXX> PawnOwner;
⑦ 在c++中,使用ScriptInterfaceCast模板函数可以将某个对象安全转换为接口类型
APawn* Enemy;
//若Enemy不为空且从IInterface_PEPPawn接口派生,则转换成功,否则返回空
TScriptInterface<IInterface_PEPPawn> IEnemy = ScriptInterfaceCast<IInterface_PEPPawn>(Enemy);
⑧ 在c++中,使用UObject的GetInterfaceAddress成员函数检查UObject实例是否实现了特定的接口
APawn* Enemy;
//若Enemy从IInterface_PEPPawn接口派生,则IEnemy不为空,否则返回空
IInterface_PEPPawn* IEnemy = (IInterfaceName*)Enemy->GetInterfaceAddress(IInterface_PEPPawn::UClassType::StaticClass());
其他参考
unrealtexture Scripting Topics
unrealtexture Scripting lessons