GPC脚本共有9个不同的部分,任何用户创建的脚本中,都应当按照下面示例中的顺序排列,因为它是脚本的核心。
Definitions(定义)
定义的唯一目的是为单词分配一个值,从而使脚本更加易于用户阅读,define
用于单词赋值、创建命名常量。定义可以放在除init
、main
、combo
或function
之外的任何位置。
语法
define <name> = <value or expression>;
<name>:常量的名称
<value or expression>:符号常量的值或表达式
定义值必须可以在编译期间计算,所以你可以使用数字,但不能使用数字函数。
示例一
define handaren= 50;
main {
if(get_val(BUTTON_8)) {
set_val(BUTTON_4, handaren);
}
}
一旦定义了一个词,并为其赋予了一个值,该词就可以在脚本中的任何有效的地方使用。
示例二
// 定义部分
define zero = 0;
define one = 1;
define two = 2;
我们将zero、one 、two分别定义为0、1、2,这些在运行时无法更改的静态值。我们在脚本的任何位置使用two这个词,代表输入数字1。
如果你想给一个词赋值并且在运行时该表它的值,你应该使用变量而不是define
data(数据)
数据部分主要目的是储存静态信息,其大小由其中的值决定,可以通过使用索引在GPC脚本中访问静态值。也可以在数据部分中使用定义。
示例一
define handaren= 255;
//索引码 0 1 2 3 4 5 6 7 8 9 10
data ( 20, 42, 35, handaren, 1, 100, 0, 86, 255, 11, 2 );
int a, b, c;
main {
a = duint8(3); //a 的数值为 255
b = dint8(3); //b 的数值为 -1
c = dint16(3); //c 的数值为 511
}
放置在数据部分中的值以字节(8位整数)表示,该指数是从零开始。第一个值是索引0,低11个值的索引是10。你也可以将更大的数字放在数据部分,但它们会导致其后的值索引为16位范围值+1,32位范围值+3。
有多个函数可以检索不同范围的数据,下表解释每个函数。
function(index)
函数名称 | 最小值 | 最大值 | 字节读取 |
dint8 | -128 | 127 | 1 |
duint8 | 0 | 255 | 1 |
dint16 | -32,768 | 32,767 | 2 |
duint16 | 0 | 65,536 | 2 |
dint32 | -2,147,483,648 | 2,147,483,647 | 4 |
示例二
// Data Section (OPTIONAL)
data (zero, one, two, 10, 128, 40);
data
部分是字节数组(8位整数),位于GPC字节码中的虚拟地址空间的开头。这些数值是只读,不能再运行时更改。例如在示例二的脚本中,我们可以这样来访问数组。
handaren3 = duint8(3); //则handaren3 = 10
const Arrays(常用数组)
const
数组部分类似于数据部分,不同之处在于它更易于管理。因为你让编译器跟踪数据的储存位置。
语法
const <datatype> <name>[] { <values> }; // 单维度
const <datatype> <name>[][] = { { <values for the first "row"> }, { <values for the second "row"> } }; // 二维度
示例一
const int8 single_dimension[] = { 0, 1, 2 };
const uint8 multi_dimension[][] = { { 0, 1, 2 }, { 3, 4, 5 } };
int a, b;
main {
a = single_dimension[1]; // 1
b = multi_dimension[1][2]; // 5
}
与数据部分的工作方式类似,所有索引在每一行中始终从0开始。如果你想访问其中数据时,需使用以下语法。
name[column];
name[row][column];
示例二
const int8 single[] = { 0, 1, 2, 3 };
const int8 two_dimensional[][] = {
{ 0, 1, 2 },
{ 3, 4, 5 }
};
Remapping(重新映射)
重新映射在脚本的开始进行定义,并且必须在主程序之前,它们不能在脚本运行时执行。
命令名称 | 描述 |
remap | 控制器输入值分配给输出 |
unmap | 断开输入与输出的连接 |
语法
remap <input_identifier> -> <output_identifier>;//重新映射语法
unmap <output_identifier>;//取消映射语法
示例一
// 重新映射
remap BUTTON_7-> BUTTON_4;
remap BUTTON_4-> BUTTON_7;
我们可以使用remap
更改控件的行为,将左按键给右按键,而右按键给做按键。
Variables(变量)
变量的值可以放在main{}
、 combo{}
或function()
之外的任何位置。这些变量是全局变量和GPC变量,可以在脚本中的任何位置访问。变量不是静态的,可以在运行时更改。
示例一
// 变量初始化
int example1 = 10;
int example2, example3;
int example4 = 17;
如果一个变量在这一段没有被赋值,那么它的初始值就是0,比如示例一中的脚本变量example2
、 example3
。
init(此处)
init
与main
类似,不同之处在于他只在脚本加载到控制器时运行一次。它可以运行与main
相同的指令与功能,例如组合和用户创建的功能。通常用于填充变量和数组以设置脚本。
示例一
// GPC 初始化
init {
if(get_controller() == PIO_PS4){
example2 = 27;
} else {
example2 = 1;
}
}
示例中,如果首次加载脚本时,转换器连接到PS4手柄,则example2
的值为27,否则其它的值为1。
main(主要)
main
是GPC脚本的核心,所有功能和组合最初都是从该位置执行的,每个GPC脚本都必须包含一个main
。
与组合和用户创建的函数不同,GPC可以只有一个主要部分。
示例一
// GPC main 部分
main {
if(example_function()){
if(get_val(example3)){
combo_run(testing);
}
}
}
转换器按照顺序运行代码,并生成输出报告,当转换器达到main
部分的结尾时,输出报告就可以发送到控制台,一旦控制台请求新数据,就会发送输出报告,并且main
开始另一次运行。
因为命令是按顺序运行,因此再多个位置设置按钮的值代表着只发送最后一个指令。
示例二
main {
set_val(STICK_2_Y, 100);
set_val(STICK_2_Y, -100);
}
例如在此脚本中LY轴的值是-100将发送到控制台,控制台u会看到LY轴设置为100,因为该空间的输出报告在发送到控制台之前已被修改。
combo(组合)
combo
是一种函数,它将按顺序执行一组指令,并在指令之后直接分配给wait
指令的时间量。
示例一
// 组合部分
combo testing{
set_val(20, 100);
wait(example1);
wait(100);
}
当组合运行时,它价格标识符20(Xbox 控制器上的 X 或 PlayStation 控制器上的 Square)设置为100%(完全按下状态)变量example1
中设置的时间(示例中10毫秒)然后再100毫秒内什么都不做。
示例二
combo LB_AND_RT {
set_val(XB1_LB, 100);
set_val(XB1_RT, 100);
wait (500);
wait (500);
}
你也可以在单个wait
语句之前分配更多命令,例如当combo
运行时,Left Bumper 和 Right Trigger 都将被按下 500 毫秒,然后它将在500毫秒内不执行任何操作。
Function(功能)
创建的function
类似于main
,命令按照顺序执行,任何在main
部分有效的GPC都可以使用,函数必须放在GPC脚本的末尾。
与函数的主要区别在于它们仅在调用时运行,并且可以返回值。当一个值从一个function
返回时,它被停止并且任何超出该点的代码都不会执行。
GPC函数是全局的,你可以从init
、main
和combo
部分调用,甚至可以从另外一个function
中调用一个function
。
示例一
// Function 部分
function example_function(){
if(get_val(example2)){
example3 = 18;
return 1;
} else if(get_val(example4)){
example3 = 19;
return 1;
}
return 0;
}