语法 (TeaScript)

来自SMBX 中文百科
< TeaScriptTeaScript/Syntax
跳转到导航 跳转到搜索

这里是有关 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"]。
'==========================================================
严重警告!千万不要把变量定义在数组下标上限以外的数组位置!否则导致游戏储存不了变量导致崩溃!(下标越界一般100%会导致程序崩溃!)

控制流

控制流,简单来说,将一段语句或数据进行判断分析,如果结果为真,就执行真部分的脚本,否则执行假部分的脚本。

If

If 语句的逻辑顺序是:当一个语句判断为真,执行表达式。
If Condition Then
    'Expression
End If
如果'Condition'返回True,游戏将执行对应的语句,然后跳到'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
一个If中可以存在多个ElseIf,但至多有一个Else,这需要注意一下。 一些例子。
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
一个'Select Case'内可有多个'Case'语句,但至多有一个'Case Else'。

游戏将先计算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
Counter 是局部变量,' Start ',' end ',' Step '是数学表达式.' Exit For '的数量无限制。执行完毕后,游戏将跳至“Next”以执行“ For”语句以外的其他语句。

如果'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]
你只能选择一组'[]',可以是'Do'之后的,也可以是'Loop'之后的,并且在'{}'内,'While'和'Loop'中也只能选择一个。

如果选择了''While'关键字,游戏会重复执行'Do'语句中的语句,直到Condition'返回真。

如果选择了''Until'关键字,游戏将重复执行'Do'语句内的语句,直到Condition'返回假。

注意!如果没有条件用来结束循环,请务必插入一个Call sleep(1)用来按游戏帧时间运行,否则会导致游戏卡死!

With

允许你将一组语句应用于给定对象。
With Object
    'execute
End With
Object 为游戏的一个对象,可以是npc,也可以是玩家,必定为一个数据变量中的其中一个,而且建议不要套娃使用! 例如要让NPC执行脚本:
With Npc(SysVal(Param1))
    .X = .X
    .Y = .Y
End With

GoTo

强制跳转到脚本的给定标签处。
FlagnName:
'Execute
GoTo FlagName
'FlagName - 标签名
'flagname'的命名规则与变量一致。在一个脚本中也不应有两个名称相同的'flagname'。不能跨函数(inter-functionally)使用'GoTo'语句,也不能在'With'中使用。

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
GoSub 一般不常用到(雾)

运算

任何脚本对数值一定的变动就需要计算,这里要用到运算符。

这里为了分清楚情况,分为了:数学表达式 和 逻辑表达式。

数学表达式

数学表达式是由数学符号和函数组成表达式的,它们经过计算后会返回一个数字。

常见的基础数学表达式如下。

数学符号 作用 例子
+ 加法 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
TeaScript 还有一个逻辑运算符:Like

常见的逻辑运算符如下:

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。

在计算机中就会这样处理:

60 << 3 在计算机中的表达
比特
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
举个例子:8 << 1 = 16 (在计算机中会这样处理: 8(1000) << 1(0001) = 16(00010000))

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
如果该函数里没有任何 Return,或任何需要返回赋值的变量,则默认返回 0 或 ""。

使用 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
Export 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留言) 的一些发现。

  1. 标记该引用符号的条目或内容,需要用户们帮忙进一步验证。