跳转到内容
模组网
icedream

【Creation Kit 学习指南 30】变量与属性

被推荐的帖子

描述

变量和属性非常相似,它们都控制着值和目标。变量是私有的,因此只有脚本使用它们并对它们赋值取值。属性本质上是被其它脚本存取的变量,其它脚本可以对其赋值取值。

如果变量或属性控制着一个数值,那么它可以存取返回这个数值。如果变量或属性控制着一个目标,那么你可以存取目标的属性或函数。(类似于从旧的脚本系统中引用变量)

声明变量

float myFloat
float myOtherFloat = 13.5
MyFloat初始值为0,myOtherFloat初始值为13.5并能通过修改脚本更改。

声明属性

完整属性

要想定义一个属性,你首先要输入类别,然后是“属性”,然后是属性的名称。接着你定义2个函数,一个用于返回变量的值,一个用于给属性赋值。然后通过"EndProperty"结束属性的定义。

例如:

int myInt_Var = 0 ; Where the property's value is stored
int property myInt
	int function get()
		return myInt_Var
	endFunction
	function set(int value)
		myInt_Var = value
	endFunction
endProperty
如果忽略取值函数,那么此属性只有其他拥有只写权限的人才能对其赋值,但是不能读取它。当然,局部脚本可以读取应用于属性的实际变量。如果忽略赋值函数,那么此属性只有其他拥有只读权限的人才能读取值,但是不能改变它。同样,局部脚本总是可以设定属性返回的变量。

你不必总是按照上述方法返回设定值 - 函数可以做任何事。例如,你可以建立一些条件待定函数,从而确保值不会溢出。或者你可以在赋值时播放动画。你不必在任何时刻都有一个实际变量 - 它可以是一个计算值或一个常量

例如:

bool property Locked
	bool function get()
		return IsLocked()
	endFunction
	function set(bool value)
		Lock(value)
	endFunction
endProperty
上述常量隐藏了锁定和已锁定目标参照函数,从而可以通过简单的设定锁定函数值的真假来锁定和解锁目标。

例如:

int myVar = 5
int property ReadOnly
	int function get()
		return myVar
	endFunction
endProperty
以上属性是只读权限。外部脚本不能改变值,但是脚本本身可以改变变量的值。

例如:

int myVar = 5
int property WriteOnly
	function set(int value)
	if value >= 0
		myVar = value
	else
		myVar = 0
	endIf
	endFunction
endProperty
以上属性是只写权限。外部脚本不能读取值,但是使用前要确保值不低于0

自动属性

自动属性书写于你设定的函数的上方,在场景旁边。有时会通过虚拟机中的少量优化使自动属性的运行速度略微提升。要想创建一个自动属性,可以如下所示在属性定义末尾加上"auto"。你可以通过语法规则"= <value>"设定属性初始值。

例如:

int property myInt = 5 auto
自动只读属性

自动只读属性是一种无法改变值的自动属性。如果你想通过使用名称而非数值借代一个属性,或者脚本中的某些数值代指不同的事物,那么设定自动只读属性将会更为方便,你可以在属性定义末尾加上"AutoReadOnly"。这些属性必须通过使用语法规则"= <value>"设定初始值。

例如:

int property myReadOnlyInt = 20 autoReadOnly
条件属性

常规属性不能通过条件声明。由于自动属性事实上在定义时隐藏由条件创建的变量,因此它可以通过条件定义。这就是为什么当你在条件系统中选择一个Papyrus变量时你会看到一个变形的自动属性名称 - 因为你从隐藏变量列表中选择。

例如:

int property myVar auto conditional
从任务脚本中获得属性

属于相同任务的结果脚本

有时你需要获得任务脚本的属性,并将其用于结果脚本。这也许很复杂,但是一旦你理解其内容,那么一切将会豁然开朗。首先观看以下案例,然后我们描述它的效果。

;打开脚本,内容如下:
scriptName MQ01Script extends Quest
int property deadCount auto

;结局脚本(属于MQ01)如下:
MQ01Script myQuest ;声明一个变量"myQuest",它是MQ01Script里的一个类别
myQuest = GetOwningQuest() as MQ01Script ;设定myQuest为它所属的任务,也就是MQ01Script类别
float myDeadCount ;声明变量"myDeadCount"
myDeadCount = myQuest.deadCount ;设定局部变量为任务属性值
;你也可以设定任务属性为:
myQuest.deadCount = 10
我们有一个属性"deadCount",它在一个与MQ01关联的脚本"MQ01Script"。我们可以设定一个属于MQ01的脚本(也许是对话结果、包结果或关联别名的脚本)。

在结果脚本中,我们创建一个反映任务脚本的变量,它有我们所需的属性(在此情况下MQ01脚本是"DeadCount"属性)。注意我们的变量myQuest由MQ01Script声明。这是因为我们设定我们的脚本"脚本名称 MQ01Script 继承于 任务",我们本质上创建一个新类型目标 - MQ01Script。GetOwningQuest返回一个任务目标(在我们继承它之前)。因此我们也需要分配由诸如"myQuest = GetOwningQuest() as MQ01Script"之类的GetOwningQuest目标返回的任务。因此我们可以存取它的继承属性。如果我们从未对其分配诸如MQ01Script之类的脚本,那么任务目标只包括函数和属性,它不会包括死循环属性。

换句话说,当我们创建一个继承于任务脚本的MQ01Script时,除非我们分配一个由GetOwningQuest返回的目标,它不会包括在新脚本中声明的新变量。

关于kmyQuest

如果我们使用的片段下拉菜单中有一个"kmyquest",那么你可以选择一个脚本并将其关联属于此片段的任务,然后使用kmyQuest"magic variable"参照任务脚本,且未分配它。

上述内容应如下所示:

float myDeadCount
myDeadCount = kmyQuest.deadCount ;getting property
kmyQuest.deadCount = 5 ;setting property
通过 Magic Effect 脚本

下面是脚本魔法访问任务属性的脚本:

Scriptname myQuestNameScript extends Quest
 
Int Property PublicInt Auto		; This value is defined as a property and can be accessed from outside this script
 
Int PrivateInt = 30			; This value is private to the script and cannot be accessed from outside this script
 
Function DamageTargBasedOnPublic(Actor akTarget)
	;This code will damage the akTarget for PublicInt damage
	akTarget.DamageAV("Health", PublicInt)
EndFunction
 
Function DamageTargBasedOnPrivate(Actor akTarget)
	;This code will damage the akTarget for PrivateInt damage
	akTarget.DamageAV("Health", PrivateInt)
EndFunction
定义了任务脚本并创建属性,我们可以从外面控制。

Scriptname mySpellEffectScript extends activemagiceffect
 
myQuestNameScript Property myQuestRef auto

Event OnEffectStart(Actor akTarget, Actor akCaster)
	myQuestRef.PublicInt = 20				; This will change the damage for the DamageTargBasedonPublic Function
	myQuestRef.DamageTargBasedOnPublic(akTarget)		; You can manipulate this damage by changing PublicDamage Prior to calling it
	myQuestRef.DamageTargBasedOnPrivate(akTarget)		; This will always do 30 damage unless the quest changes the private variable
EndEvent
然后你需要查看属性窗口了解你的脚本附属于哪里,然后设置myQuestRef的属性为任务脚本相关联的任务。

从任何其他脚本

你可以使用上面Magic Effect的脚本参考。你必须在脚本中定义属性,以及你需要访问的对象“类型”。如果你的对象有自定义脚本,定义该类型为对象的脚本名字。注意不要声明为对象名字。所有的对象都可能有多个脚本,所以你必须指定你要访问的脚本名字。

ScriptName ScriptA extends Quest
 
int Property intProperty Auto
float Property floatProperty Auto
GlobalVariable Property gvProperty Auto
Shout Property shoutProperty Auto
因为我们想要获取或者修改 ScriptA 的属性,我们需要再新建脚本 ScriptB:

ScriptName ScriptB extends Quest
 
int iVar
float fVar
GlobalVariable gVar
 
 
ScriptA property MyScriptProperty
	ScriptA Function Get()
		If !GetData
			GetData = True
			ReturnVal = (Self as Quest) as ScriptA
		EndIf
		return ReturnVal
	EndFunction
	Function Set(ScriptA NewValue)
		If !SetData
			SetData = True
			ReturnVal = NewValue
		EndIf
	EndFunction
Endproperty
Bool GetData = False
Bool SetData = False
ScriptA ReturnVal
 
Event OnInit()
        MyScriptProperty.intProperty = 10    ;sets intProperty to 10
        MyScriptProperty.floatProperty = 5.5   ;sets floatProperty to 5.5
        MyScriptProperty.gvProperty.SetValue(10)   ;sets gvProperty to 10
        MyScriptProperty.gvProperty.GetValue()     ;returns 10
        MyScriptProperty.shoutProperty     
endEvent
游戏中可以使用为类型的所有对象看Script Objects

另外参考:Accessing Functions From Other Scripts

警告

谨慎处理由多个其他脚本扩展的"基础"脚本的变量和自动属性。这是因为可能会遇到多个脚本含有相同的变量或者自动属性关联到相同的对象,然后游戏可能无法可靠的选择变量或者属性。

举个例子,下面的3个短脚本:

ScriptName Base extends ObjectReference

Int Property MyValue Auto
ScriptName Derived1 extends Base
ScriptName Derived2 extends Base
因为Derived1和Derived2扩展了Base,他们各自都继承了MyValue属性。

然后,想象创建一个对象,然后脚本Derived1和Derived2都依附上去。尝试访问MyValue将不会返回相同的数值:

(MyObjectReference as Base).MyValue
这是声明在本地脚本对象的双真变量和自动属性,比如Actor Script。因为游戏可以在任何需要的时候归属这些到游戏中的对象,所以会创建另一个副本变量或者属性。

为了避免这类情况发生,请不要编辑本地脚本对象,并且当单个对象有多个脚本附属并继承相同的属性,请确认你在访问属性之前要把它转换成最直接的表单。在上面的例子中,可以使用:

(MyObjectReference as Derived1).MyValue
注意
  • 属性对话框中的属性列表只在添加新属性或在脚本被汇编后才会更新。

分享此帖子


帖子链接
分享到其他网站

创建账户或者登录再讨论

您需要成为会员才能留下讨论

创建账户

在本社区注册新账户。很简单的!

注册为新账户

登录

已有账户?这边登录

马上登录

×
×
  • 新建...