语法 (TeaScript)
这里是有关 TeaScript 的语法写法。
语言写法逻辑与 Visual Basic Script 相似。(有的语法与 Visual Basic 6 相似,但略有区别。)
数据类型和变量
变量可以从关卡里创建,在编辑器里按Ctrl+I,即可弹出“Variables”页面,然后点击“New”,即可创建变量。所定义好的变量就是本地变量,调用时输入Val(NewVariable1)
,即可调用。注意的是,创建一个数据变量的同时,也自动创建了一个字符串的变量。
赋值变量种类通常是:
- Double Variable 双精度型变量
- String Variable 字符串变量
某些系统功能使用了另一种变量类型 — Name。
Name 表示着某种东西的名字, 你不需要用引号来表示它的值。
变量名只能使用数字、字母以及它们的组合。变量名不区分大小写。变量名不能存在空格。
赋值变量
双精度浮点型变量
双精度浮点型变量是计算机使用的一种数据类型,使用 64 位(8字节) 来存储一个浮点数。 它可以表示十进制的15或16位有效数字,其可以表示的数字的绝对值范围大约是:-1.79E+308 ~ +1.79E+308。
调用输入Val(NewVariable1)
,可以在变量面板里修改,也可以在脚本里输入Val(NewVariable1) = xxx
修改。
字符串变量
字符串变量是基于变量的另一种类型,一般由字符和数字组成。但事实上当你定义了一个局部/全局变量的同时,你也定义了一个同名的字符串型局部/全局变量。
调用输入Str(NewVariable1)
。注意,字符串没法在变量窗口直接修改!需要在脚本里用Str(NewVariable1) = "xxx"
修改。
数据类型
本地变量
本地变量是指在关卡内创建好的以Val(NewVariable1)
为变量的变量类型,也说明该变量只能在一个关卡使用,在其他关卡调用将会报错或被其他变量替换。
本地变量可以从关卡编辑模式内的变量窗口创建。
全局变量
全局变量是指在世界内创建好的以GVal(NewVariable1)
为变量的变量类型,也说明该变量可以在当前世界的任何关卡使用。
全局变量可以从世界编辑模式内的变量窗口创建,并且在该世界下的所有关卡都可以调用。
定义变量
定义变量是指在关卡内或世界内脚本区里往一个脚本创建Dim Variable As Type
变量。该变量无需任何前缀或后缀,直接输上该变量名即可读取。
Dim a As Integer = 10 '定义一个双字节整数变量 a 并赋予 10。
Dim b As Integer = 9 '定义一个双字节整数变量 b 并赋予 9。
Dim c As Integer '定义一个双字节整数变量 c 。
c = a + b '把 c 赋值为 a+b 的和。
Call ShowMsg(c)
'当执行到ShowMsg的时候,显示 19.
数组
数组是一些数的组合,相当于一个组里有若干个数字或字符串。
只能在关卡内变量窗口按 Shift 然后点击 "Add" 才能创建,但还不能立即使用,因为虽然创建了数组,但该数组在程序所占的内存是没有的,相当于一个数字都没有,因此需要Call ReDim( 0 , ArrayName , Count )
来定义好数组的内存个数,以及重新调整内存个数。
Array(ArrayName(x))
来储存变量了!同样,数组下标开始位置是[0]。'假设你创建了两个数组,一个用于储存数字变量,一个用于储存字符串变量。
'分别叫:MyArray 和 MyStrArray。
'==========================================================
Call ReDim(0,MyArray,3) '重建数组 MyArray 的下标数为 3
Call ReDim(0,MyStrArray,3) '重建数组 MyStrArray 的下标数为 3
Array(MyArray(0)) = 5 '赋予数组 MyArray 的[0]下标的值为 5
Array(MyArray(1)) = 9 '赋予数组 MyArray 的[1]下标的值为 9
Array(MyArray(2)) = Array(MyArray(0)) + Array(MyArray(1)) '赋予数组 MyArray 的[2]下标的值为 MyArray[0]+MyArray[1]的和。
Array(MyStrArray(0)) = "Hello" '赋予数组 mystarray 的[0]下标的值为 "Hello"
Array(MyStrArray(1)) = "SMBX"
Array(MyStrArray(2)) = Array(MyStrArray(0)) & " " & Array(MyStrArray(1))
Call ShowMsg(Array(MyArray(2))) '14,要调用数组,输入 Array( MyArray (x) ) 。x为下标数,从[0]开始计。
Call ShowMsg(Array(MyStrArray(2))) ' "Hello SMBX"
'该数组 MyArray 的数据是: MyArray = [5, 9, 14]。
'该数组 MyStrArray 的数据是: MyArray = ["Hello", "SMBX", "Hello SMBX"]。
'==========================================================
控制流
控制流,简单来说,将一段语句或数据进行判断分析,如果结果为真,就执行真部分的脚本,否则执行假部分的脚本。
If
If 语句的逻辑顺序是:当一个语句判断为真,执行表达式。If Condition Then
'Expression
End If
另外还有两种方式。
If ... Else
If Condition Then
'Expression True
Else
'Expression False
End If
If ... ElseIf ... Else
If "Condition 1" Then
'Expression Condition 1 True
ElseIf "Condition 2" Then
'Expression Condition 2 True
'...
ElseIf "Condition n" Then
'Expression Condition n True
Else
'Expression all Conditions False
End If
Dim a As Integer = 0
Do
a += 1
If a = 64 Then
Exit Do
End If
Loop
Dim a As String = "Mario"
If a = "Mario" Then
Call ShowMsg("Mario")
Else
Call ShowMsg("Luigi")
End If
With Char(1)
If .Status >= 2 Then
.Status = 1
ElseIf .Status = 1 Then
.Status = 1
Else
Call SpEvent(2)
End If
End With
Select Case
Select Case 是一个分支逻辑判断程序,其作用是将一个表达式的结果,按照定义好的结果对比执行结果。Select Case "text Expression"
Case "Expression 1"
'execute Expression 1 If "text Expression = Expression 1 = True".
Case "Expression 2"
'execute Expression 2 If "text Expression = Expression 2 = True".
...
Case "Expression n"
'execute Expression n If "text Expression = Expression n = True".
Case Else
'execute this Expression If "text Expression = Expression any = False".
End Select
游戏将先计算test-Expression并获得其返回值,然后搜索Case之后的experssion的返回值是否与test-Expression的返回值一致。
如果一致,游戏将立即执行其后的语句并跳转至“End Select ”执行其他语句。
一个例子。Dim a As Integer = 60
Dim b As Integer = 0
Select Case a
Case 0 to 59
a += 1
Case 60
b += 1
a -= 60
Case Else
a = 0
End Select
For
For 是用来定义一个重复执行的语句段。其原理是,先定义好要开始的表达式,然后按步长表达式执行,直到定义结束的表达式为止。For Counter = Start To End Step Steps
'Execute
'你可以在里面塞一个 Exit for 来结束该循环语句。
next
如果'step'没有设置的话,其将被设为默认值1。
当执行'For'语句时,游戏会将'start'的值发送到局部变量'counter'中,然后执行'execute'。当执行至'Next'时,游戏会将步长值加到'counter'并将'counter'变量的值与'End'比较。如果'counter'的值大于'End',则游戏将跳至'Next',并执行'Next'之后的语句,否则游戏将在'For'语句内重复执行语句。
一个例子。For Val(a) = 1 To 10 Step 2
Call ShowMsg(CStr(a))
If Val(a) = 5 Then
Exit For
End If
Next
'Show:
'1
'3
'5
Do
Do 将重复执行它所包含的语句。Do '[{While|Until} Condition]
'Execute Scripts
'你可以塞一个 Exit Do 用来结束这个循环。
Loop '[{While|Until} Condition]
如果选择了''While'关键字,游戏会重复执行'Do'语句中的语句,直到Condition'返回真。
如果选择了''Until'关键字,游戏将重复执行'Do'语句内的语句,直到Condition'返回假。
注意!如果没有条件用来结束循环,请务必插入一个Call sleep(1)
用来按游戏帧时间运行,否则会导致游戏卡死!
With
允许你将一组语句应用于给定对象。With Object
'execute
End With
With Npc(SysVal(Param1))
.X = .X
.Y = .Y
End With
GoTo
强制跳转到脚本的给定标签处。FlagnName:
'Execute
GoTo FlagName
'FlagName - 标签名
GoSub
'GoSub' 是'GoTo' 的替代版,但又有不同点。 当它们被执行时,程序也将被强制跳转到给定行。与'GoTo'语句不同的是,'Return'语句可以紧跟其后。当'Return'语句被执行时,程序将返回到对应的'GoSub'语句的下一行并继续执行。如果'Return'语句不包含'GoSub'语句,则将忽略它。与'GoTo'语句类似,'GoSub'语句不能在'With'语段内中使用,也不能在跨函数使用,如果脚本或函数退出时没有退出所有'GoSub'语句,则当前结构中的返回堆栈将被清除。'GoSub'语句不会影响Sleep函数的可用性,因此Sleep函数可以在子过程中使用,在这种情况下,返回堆栈不会被清除。GoSub Script.Line
'script.line - 给定行
MySub:
Val(a) = Val(a) + 1
If Val(a) < 10 Then
GoSub MySub
End If
Return
运算
任何脚本对数值一定的变动就需要计算,这里要用到运算符。
这里为了分清楚情况,分为了:数学表达式 和 逻辑表达式。
数学表达式
数学表达式是由数学符号和函数组成表达式的,它们经过计算后会返回一个数字。
常见的基础数学表达式如下。
数学符号 | 作用 | 例子 |
---|---|---|
+ | 加法 | 1 + 1 = 2 |
- | 减法 | 5 - 4 = 1 |
* | 乘法 | 9 * 8 = 72 |
/ | 除法 | 21 / 7 = 3 5 / 4 = 1.25 |
Mod | 模除法 (取余) | 16 Mod 7 = 2 |
\ | 无余除法 (无小数) | 39 \ 18 = 2 |
^ | 乘方 | 2 ^ 6 = 64 |
& | 连接符号 (一般字符串常用) | 2 & 3 = 23 "Hello" & "World" = "HelloWorld" |
() | 括号 | (5 + 9) / 7 = 2 |
<< | 左移位 | 32 << 1 = 64 |
>> | 右移位 | 32 >> 1 = 16 |
数学函数名字 | 全称 | 作用 | 例子 |
---|---|---|---|
Abs | Absolute Value | 返回绝对值 | Abs(-1) = 1 |
Sin | Sine Function | 返回正弦数 | Sin(Pi) = 1 |
Cos | Cosine Function | 返回余弦数 | Cos(Pi) = -1 |
Tan | Tangent Function | 返回正切数 | Tan(Pi) = 0 |
Atn | Arctangent Function | 返回反正切数 | 4*Atn(1) = 3.141593 |
Log | Logarithms Function | 返回对数 | Log(e) = 0.434294 |
Sgn | Sign Function | 返回参数的符号值 | Sgn(5) = 1 Sgn(-5) = -1 |
Fix | Fix Function | 取整数非四舍五入 | Fix(9.28) = 9 Fix(-7.22) = -7 |
Int | Int Function | 向下取整为最接近的整数 | Int(4.44) = 4 Int(-4.44) = -5 |
Sqr | Square Root | 返回参数开平方后的结果 | Sqr(2) = 1.414214 |
Rnd | Random | 返回0到1间的随机数 | 5*Rnd = 4.201952
5*Rnd = 1.260157 5*Rnd = 2.301802 5*Rnd = 2.860466 5*Rnd = 3.150863 |
特殊值
该程序里有一些特殊常量,他们代表一个固定的数值。
常量名 | 描述 | 数值(取自游戏内的值) |
---|---|---|
Pi | 圆周率的值 | 3.14159274101257 |
e | 自然对数底数的值 | 2.71828174591064 |
Rnd | 随机数的值,取值为0~1。
随机值种子随时间的变化而变化。 |
0 ~ 1
取小数位15位。 |
逻辑表达式
逻辑表达式是用来表示参数满足的条件,在大多数语言里,大多是以布尔变量 (Boolean Variable) 表示,但在SMBX,则使用0或1代替。(不可将变量设置为布尔类型,因为不存在该类型变量。)
它们会告诉你表达式是否为真(True)。 经过运算后,结果将得到 0 (表示假,即False)或 1 (表示真,即True)。
逻辑表达式符号有两种类型:比较运算符和逻辑运算符。比较运算符的优先级要高于逻辑运算符。
同样,逻辑运算符也可以计算一个变量和另一个变量的二进制的关系。
常见的比较运算符如下:
比较符号 | 作用 | 例子 |
---|---|---|
< | 小于 | 8 < 9 --> True 9 < 8 --> False |
> | 大于 | 8 > 9 --> False 9 > 8 --> True |
<= | 小于等于 | 9 <= 8 --> False 8 <= 8 --> True |
>= | 大于等于 | 8 >= 9 --> False 9 >= 9 --> True |
= | 等于 | 8 = 9 --> False 9 = 9 --> True |
<> | 不等于 | 9 <> 9 --> False 9 <> 8 --> True |
常见的逻辑运算符如下:
P | Q | P And Q | P Or Q | Not P | Not Q | P Xor Q | P Eqv Q | P Imp Q |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 |
1 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 |
非(Not):将真假值互换,正如上面所提到的当a为0时,Not a(即非a)为1;
与(And):a、b同真运算结果为真;
或(Or):a、b有真运算结果为真;
异或(Xor):当两个表达式的值不同时(即一个为True,另一个为False),其结果为True;当两个表达式的值相同(都为True或都为False)时,结果为False。也就是“异"则“真”,“同”则“假”;
逻辑相等(Eqv):与“异或"运算是一对互逆运算符,即当两个表达式的值相同(都为True或都为False) ,其结果为True;当两个表达式的值不同(一个为True,另一个为False)时,其结果为False。只要表达式中有一个为Null,则结果为Null;
蕴含(Imp):Result=Expressionl Imp Expression2 只有当第一个表达式Expressionl为True,第二个表达式expreesion2为False时,结果才为False,其他情况下结果均为True。
例子:Dim a As Byte
Dim b As Byte
Dim c As Long 'This is Result Parameters
a = 60 '60 = 0011 1100
b = 13 '13 = 0000 1101
c = a And b 'Result: 0000 1100 = 12
c = a Or b 'Result: 0011 1101 = 61
c = a Xor b 'Result: 0011 0001 = 49
c = Not a 'Result: 1100 0011 = -60
c = Not b 'Result: 1111 0010 = -13
c = a Eqv b 'Result: 1100 1110 = -49
c = a Imp b 'Result: 1100 1111 = -48
移位表达式
关于移位(<< 或 >>),在 TeaScript 照样适用(于 2021.9.13 发现。)
同样,逻辑运算符也可以进行计算,具体原理可以参考:W3CSchool 演示
移位的用途,可以使用一个 Byte 类型的Dim变量来控制某样事件或决定那些事件需要触发。
运行原理是,每个数值在计算机中都是以二进制存储,比如60,在二进制的数据就是 00111100,此时,想将所有的1向左移动3位,那么只需要输入xxx = 60 << 3
,就能得到运算结果为480。
在计算机中就会这样处理:
比特 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
12 | 11 | 10 | 9 | - | 8 | 7 | 6 | 5 | - | 4 | 3 | 2 | 1 | ||
原数 | 60 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | ||
移位1 | 120 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | ||
移位2 | 240 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | ||
移位3 | 480 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
25(00011001) >> 2 = 6(00000110),其余的0会被忽略。
函数
函数是指一段可以直接被另一段程序或代码引用的程序或代码。也叫做子程序、(OOP中)方法。
一个较大的程序一般应分为若干个程序块,每一个模块用来实现一个特定的功能。所有的高级语言中都有子程序这个概念,用子程序实现模块的功能。在C语言中,子程序的作用是由一个主函数和若干个函数构成。由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。
在 TeaScript 里,有很多种函数,它们大多数使用来控制游戏的运行或控制变量,再或者创建物体等等操作。
一些函数可以被变量赋值(只要这个函数包含返回函数 Return xxxx)。
一些游戏里定义好的函数,请去 函数 (TeaScript) 查看。
自定义函数
TeaScript 允许你在脚本里创建一个自定义函数,但有个缺点就是没办法跨函数使用。而且一般要写在该程序的末尾处,不论在哪一行,程序都会先检测是否有函数,然后应用,之后在任意一行调用该函数即可运行该函数里的语句。
函数一般为:“Procedure (过程,不含 Return 的函数)和 Function (函数,含 Return 的函数)”
Function 的语法
' type must be double or String
Script FunctionName(Param1 As Type, Param2 As Type, ..., Return Type)
' to access a parameter, just type the name
Return Value
End Script
使用 Val(a) = FunctionName(Param1,Param2...)
或 Call FunctionName(Param1,Param2...)
都可调用。
Procedure 的语法
' type must be double or String
Script ProcedureName(Param1 As Type, Param2 As Type, ...)
End Script
Call ProcedureName(Param1,Param2...)
调用。
Export 的语法
该语法允许你将该函数变为允许跨函数使用的函数,并在其他脚本调用该函数。[需要验证 1]
' This function can now be accessed in any script
Export Script ProcedureName(Param1 As Type, Param2 As Type, ...)
End Script
' === Example
Dim x As Integer = 5
Dim y As Integer = 10
Dim z As Integer
z = Max(5, 10)
' z Returns 10
' This script Returns the larger parameter
Script Max(a As Double, b As Double, Return Double)
If a > b Then Return a
Return b
End Script
' === Example
' This disables both types of jumps
Call SetJumps(-1)
' This enables both types of jumps
Call SetJumps(0)
Script SetJumps(x As Double)
SysVal(DisableJump) = x
SysVal(DisableSpinJump) = x
End Script
问题
以下片段全部引用于https://wohlsoft.ru/pgewiki/TeaScript_Syntax,翻译不一定100%标准,如果出现错误请及时修正。
下面是你在使用 TeaScript 时可能会遇到的一些问题。
ScriptPtr
该函数允许修改现有脚本的参数。这个函数很可能正在开发中,因为它总是返回一个错误。Call ShowMsg(Hello("a"))
Script Hello(t As Double, Return Double)
Return 0
ScriptPtr Hello(t As String, Return Double)
Return -1
End
在全局脚本上使用定义变量
由于某些原因,在全局脚本中使用Long, Single或Double类型将在开始游戏模式时返回一个错误。
但是,Byte和Integer类型可以很好地工作。
> 这些问题都在 1.4.5 修复<
在 If 控制流里使用 Dim Variables [Patch 31 中被修复!]
如果你在If语句中初始化一个dim变量,它会产生 bug 效果。这是 TeaScript 身边的一个bug。
' This is a bug If -1 = -1 Then Dim i As Double = 1 Call SysShowMsg(i,0,0) Dim j As Double = i - 2 Dim k As Double = j + i Call SysShowMsg(i,0,0) Call SysShowMsg(j,0,0) Call SysShowMsg(k,0,0) End If
小数问题
如果在写小数的时候如果省略掉前面的0,则会出现错误。
'Wrong v(myVar) = .1 'Correct v(myVar) = 0.1
负数问题
写负数时,请确保前面没有其他符号(除了括号)。'Wrong (Teascript errors due to seeing * and - next to each other)
v(myVar) = 5*-4
'Correct
v(myVar) = 5*(-4)
v(myVar) = -4*5
死循环
当你使用 Do 写一个循环的时候,请,务必,务必!写上Sleep(1)
以让该循环按每游戏帧循环运行!!!
如果不这样做的话,那么游戏会一直无限死循环运行下去该函数,这样会导致游戏卡死。
这种死循环在 For,Flags 以及任何有循环运行的控制流上也同样奏效。
下面是一些错误的例子。Dim a As Integer
Do
a += 1
Loop
'千万不要这样写!如果尝试在游戏中运行,会导致游戏卡死!
变量
你在关卡里 Ctrl+i 打开的变量面板中创建的变量,在 TeaScript 中是Val(variable)
或v(variable)
,在世界里 Ctrl+i 打开的变量面板中创建的变量,在 TeaScript 中是GVal(variable)
,gv(variable)
或&gvl(variable)
(赋予字符串时使用)。
Val 与 var 有点相似,如果不注意就有可能产生错误,var 是 JavaScript 或其他语言的赋值函数。(曾经我也犯过这样的错误。Rosalina129(留言) 2022年3月5日 (六) 07:52 (CST))
引用
https://wohlsoft.ru/pgewiki/TeaScript_Syntax
https://unrealneo.miraheze.org/wiki/SMBX/Script/TeaScript/Control
相关群文件的 Super Mario Bros.X 脚本帮助 (功能猎手版)。
以及 Rosalina129(留言) 的一些发现。
- ↑ 标记该引用符号的条目或内容,需要用户们帮忙进一步验证。