零基础开发 era 游戏 #5 变量的声明 / 定义

唯二的变量类型:(整型)数值 / 字符串#

era basic 中只有两种变量类型:

  • 数值:确切的说是「整型(整数类型)数值」。
    是的,era 里面是不存在小数(浮点数)的。当然你可以自行实现。
  • 字符串:就是字符串。

一般情况,若没有特别指定 S 后缀(字符串String),则默认该变量为数值类型。
比如:

变量用途数值类型字符串类型
通用返回值RESULTRESULTS
通用局部变量LOCALLOCALS
通用形式参数ARGARGS
……

当然,这是系统预设的内置变量的命名规范,你可以按自己的喜好来命名。
比如我就要定义变量 NUMS 为数值,CHAR 为字符串,谁能拦我?!谁也管不着你

数组变量#

Emuera 是支持数组的,当然也是分数值数组 / 字符串数组。
并且支持多维数组,不过最多到三维。
数组取指定下标的值使用英文半角冒号 :,多维数组就继续套娃,如

ARRAY:(index_a):(index_b):(index_c)  ; 最多三维 四维数组定义时就会报错
ARRAY:index_a:index_b:index_c        ; 当下标不存在歧义时 括号可以省略

ARRAY:(idx + 1)                      ; 当下标需要先计算时 必须用括号包起来
ARRAY:idx + 1                        ; 视为 (ARRAY:idx) + 1
; 某种程度上可以认为 [: 运算符] 比 [其他运算符] 优先

ARRAY:0                              ; 当下标为 0 时(取数组第一个值)可以直接省略
ARRAY == ARRAY:0                     ; 实际上 RESULT / LOCAL / ARG 其实都是数组

系统内置变量#

LOCAL / LOCALS#

顾名思义,本地local(局部)变量,仅在当前作用域(当前函数内部)生效。

@SYSTEM_TITLE
    LOCAL:10 = 123   ; SYSTEM_TITLE 函数里的 LOCAL:10
    CALL TEST        ; 调用 TEST
    ; 你改的是 TEST 里的 LOCAL:10
    ; 跟我 SYSTEM_TITLE 里的 LOCAL:10 有什么关系?
    PRINTV LOCAL:10  ; 原样打印 123
    QUIT


@TEST
    LOCAL:10 = 999  ; 修改 TEST 函数里的 LOCAL:10
    RETURN

由于和「函数」强相关,更多细节请到《函数》一章中了解。

ARG / ARGS#

顾名思义,形式参数argument,仅在函数内部生效。

@SYSTEM_TITLE
    CALL TEST(11, 13, 777)
    PRINTV RESULT  ; 打印 24(11 + 13)
    QUIT


@TEST, ARG:0, ARG:1, ARG:1100
    LOCAL = ARG:0 + ARG:1
    RETURN LOCAL

本来 ARG 的大小默认只有 1000,但这里不会报错。
是因为使用了 ARG:1100,会自动将 ARG 数组的大小扩张到 1101(0 ~ 1100)。

系统内置数组变量大小#

所有系统内置变量都可以用特殊的 csv 文件 VariableSize.csv 来设定变量大小。
编辑 ./csv/VariableSize.csv,格式类似 变量名,变量数组大小

RESULT,100
COUNT,100
A,-1
B,-1
C,-1
D,-1
E,-1
F,-1
G,-1
  1. 一般来说,VariableSize.csv 设置的数组大小最小为 100,再小会报警告。
  2. 禁用某个变量必须将其设置为 -1,而不是 0

当值为 -1 时,即注销此变量。(想要使用需要自行定义该变量)

系统内置全局变量#

作用配置项名配置项类型配置项变量名
自定义标题栏ウィンドウタイトル字符串WINDOW_TITLE
游戏制作者作者字符串GAMEBASE_AUTHOR
游戏信息追加情報字符串GAMEBASE_INFO
发布时间製作年字符串GAMEBASE_YEAR
游戏名タイトル字符串GAMEBASE_TITLE
游戏 IDコード数值GAMEBASE_GAMECODE
游戏版本号バージョン数值GAMEBASE_VERSION
最低兼容版本バージョン違い認める数值GAMEBASE_ALLOWVERSION
默认角色编号最初からいるキャラ数值GAMEBASE_DEFAULTCHARA
禁用物品系统アイテムなし数值GAMEBASE_NOITEM

编辑 ./csv/GameBase.csv,格式类似 配置项,配置值

;----------------------------------------------------------------
; 游戏基本信息 GameBase.csv
;----------------------------------------------------------------

; 自定义标题栏 [WINDOW_TITLE]
ウィンドウタイトル,游戏窗口标题栏显示的标题

; 游戏作者 [GAMEBASE_AUTHOR]
作者,作者名称

; 游戏 slogan [GAMEBASE_INFO]
追加情報,这是一条游戏相关信息

; 游戏发布时间,注意是字符串,即兼容类似「1886 ~ 至今」的格式 [GAMEBASE_YEAR]
製作年,1905 ~ 至今

; 游戏名 [GAMEBASE_TITLE]
タイトル,一个 era 游戏

; 游戏标识号码,相当于 era 的身份证,以保证别的 era 游戏的存档不能和你的混用 [GAMEBASE_GAMECODE]
コード,114514

; 游戏刚开始时就存在的角色编号 [GAMEBASE_DEFAULTCHARA]
最初からいるキャラ,1

; 游戏当前版本号,显示时会除以 1000(比如 0101 会变成 0.101) [GAMEBASE_VERSION]
バージョン,0001

; 游戏当前支持的最低版本,低于此版本的存档会拒绝读取 [GAMEBASE_ALLOWVERSION]
バージョン違い認める,0001

; 是否取消物品道具系统 [GAMEBASE_NOITEM]
アイテムなし,1

WINDOW_TITLE 为空时,自动由 GAMEBASE_TITLE + GAMEBASE_VERSION 组成。
此外,标题栏 WINDOW_TITLE 也是一个变量,也就是说你可以在游戏里动态改变标题。

@SYSTEM_TITLE
    WHILE 1
        TWAIT 1000, 1
        WINDOW_TITLE '= @"%GETTIMES()% 编程,很神奇吧?"
    WEND
    QUIT

另外还有两个有趣的系统内置常量(无法动态改变),分别是:

  • MONEYLABEL:货币单位符号,默认为美元符号 $
  • DRAWLINESTR:分隔线本体,DRAWLINE 其实就是把它打印出来。
    PRINTSL DRAWLINESTR = DRAWLINE

说是无法改变,但启用 _Replace.csvを利用する:YES 设置项后可以事先在 ./csv/_replace.csv 文件编辑 お金の単位DRAWLINE文字 两项来改变。

自行声明 / 定义一个变量#

一般来说,对于变量,声明 / 定义变量指的是同一件事:创建一个变量。
我们使用 #DIM(定义数值)/ #DIMS(定义字符串)关键字来实现。

参考上一节,#DIM / #DIMS 其实已经限定了变量的类型。

@TEST
    #DIM 一个数值变量
    #DIMS 一个字符串变量
    ; 你当然可以用中文作为变量名 但非常不推荐
    ; 你可能会想: 很多 era 游戏本体就是大量使用日文变量名 这是事实
    ; 但这是非常不好的习惯 这也是事实 不要学他们
    #DIM num                               ; 没有设定初始值的数值
    #DIMS word                             ; 没有设定初始值的字符串
    #DIM a_num = 123                       ; 设定初始值的数值
    #DIMS words = "noot noot"              ; 设定初始值的字符串
    #DIMS many_words = "are", "you", "ok"  ; 设定初始值的字符串数组

没有特别设定初始值的情况:

  • 数值变量初始值为 0
  • 字符串变量初始值为 ""(空字符串)

一般来说,不赋初始值,仅仅只是起个名,叫做「声明」。
赋初始值(准确地说是为其开辟内存空间)叫做「定义」。
这个不考,稍作了解即可。

数值变量#

虽说只有整型数值,但也有很多不同写法。

@TEST
    #DIM num

    num = 32        ; 十进制
    num = 0x20      ; 十六进制 hexadecimal
    num = 0b100000  ; 二进制 binary
    num = 1p5       ; 1 × 2 的 5 次方(即二进制的 1 后面 5 个 0)

    num = 1e5       ; 1 × 10 的 5 次方(即 1 后面 5 个 0)

上面四种表达方式都是「将 num 赋值为 32」,最后一种是 100,000

定义数组变量#

@TEST
    ; 没有定义数组上限 自动取初始值的元素数量
    #DIM three_num = 1, 2, 3

    ; 定义的数组上限超过初始值的元素数量 没有指定初始值的其他项均为默认初始值
    #DIM hundred_num, 100 = 4, 5, 6
    ; hundred_num:99 == 0

    ; 初始值元素数量超过定义的数组上限
    ; 报错「初期値の数が配列のサイズを超えています」
    #DIM error_num, 2 = 7, 8, 9

    ; 字符串数组变量同理
    #DIMS three_str = "A", "B", "C"

动态变量#

@SYSTEM_TITLE
    #DIM timer = 10
    WHILE timer--
        CALL TEST
    WEND
    QUIT


@TEST
    #DIM DYNAMIC dynamic_cnt
    #DIM normal_cnt
    dynamic_cnt += 1
    normal_cnt += 1
    PRINTFORML dynamic={dynamic_cnt} normal={normal_cnt}

加上 DYNAMIC 关键字,每次调用时都会重新初始化一个该变量。
可以用来兼容循环 / 递归调用。

静态变量(常量)#

@TEST
    ; 没有定义数组上限 自动取初始值的元素数量
    #DIM CONST const_array = 1, 2, 3

    ; 初始值与定义的数组上限不符
    ; 报错「定数の初期値の数が配列のサイズと一致しません」
    #DIM CONST const_big_array, 100 = 4, 5, 6

    ; 字符串数组变量同理
    #DIMS CONST const_str_array = "A", "B", "C"

引用型变量#

@SYSTEM_TITLE
    #DIM num = 10
    PRINTVL num     ; 10
    CALL TEST(num)  ; 10 + 5
    PRINTVL num     ; 15
    QUIT


@TEST(argv)
    #DIM REF argv
    argv += 5

加上 REF 关键字之后,将传递的参数变为实参。
即直接将该变量所在内存地址的「引用」传递到调用的内部函数,在内部函数中处理时由于是直接处理的该值本身,无需返回,外部函数就能获得处理结果。

传递数组的引用

值得一提的是,由于 Emuera 所有的变量在语义上的本质都是「数组」——
因此,传递变量引用是可以将「整个数组」都传进函数内部的。(而且兼容数组下标)

不过无论传是哪个元素:array(即 array:0 的简写)、array:1array:2……其实都是将 array 的基址(或者说存储 array容器,即 整个数组)传进函数。

@SYSTEM_TITLE
    #DIM array, 10
    array = 10
    array:1 = 20
    array:2 = 30
    CALL TEST(array:1)
    QUIT


@TEST(list)
    #DIM REF list
    PRINTL 尽管你写的是传 array:1
    PRINTL 其实传的还是 array 这一整个数组
    PRINTFORML list={list} 其实是 list:0={list:0}
    PRINTFORML 其他元素也一起传进来了 list:1={list:1} list:2={list:2}

使用变量#

数值变量直接操作即可。

这里重点讲下字符串变量,字符串变量有两个赋值操作符:='=

@TEST
    #DIM CONST the_num = 123
    #DIMS CONST the_str = "ABC"
    #DIMS temp = "第一个字符串变量", "第二个字符串变量"
    PRINTFORML temp:0=%temp:0%
    PRINTFORML temp:1=%temp:1%
    temp:0 = 右边的内容原封不动的赋值给左边 "包括引号和空格" {the_num} %the_str%
    temp:1 '= "右边的内容需要为一个完整的字符串 " + GETTIMES() + @" {the_num} %the_str%"
    PRINTFORML temp:0=%temp:0%
    PRINTFORML temp:1=%temp:1%

如果要类比的话:

  • = 类似 (PRINT)FORM
  • '= 类似 (PRINT)S

lackbfun © 2021 - 2024