Skip to content

grammar

laishikai edited this page Apr 24, 2021 · 30 revisions

返回主页

基础数据类型

支持所有C基础数据类型

char, bool, byte, short, ushort, wchar, int, uint, float, int64, uint64, double

支持所有C操作符

++, --, +, -, *, /, %, ?, (), =, +=, -=, *=, /=, >>, <<, >>=, <<=, >, <, ==, >=, <=, &&, ||, &, |, ^, !, ~, ->, . ,

对于int数据类型,操作符运算有额外的优化,运算效率最高,建议尽量使用int数据类型

FCType

可表示自定义类的类型或跨平台导入类的类型

FCType类接口

FCType nType = typeof(CTest)

FCObject

通用的class指针,可指向自定义的或外部导入的类

FCObject类接口

IntPtr

跨平台的指针,可以将脚本的字符串对象,或数组的数据转换成IntPtr, 传递给宿主语言,用于高效的数据传输

字符串类

StringA utf8编码的字符串

StringW utf16编码的字符串

StringA 与 StringW 可以相互赋值

字符串类接口

数组模板类

数组不分动态与固定,都是动态数据,不管是new出来的, 都是数组对象,都可以调用数组的接口方法

初始化方法一

char []array = new char[100];

初始化方法二

List <char> array = new List <char>();

初始化方法三

int []array = {1, 2, 3, 5, 8, 9};

数组的显式释放

array = NULL;

List模板接口

List不支持List或map的嵌套

map, 模板类

map <key, value>

map模板接口

map不支持List或map的嵌套

list, map为什么不支持嵌套,主要是为了性能,也是为了简化VM的代码

系统函数接口

系统函数接口

序列化流

序列化接口

if

语法与C, C++, C#语法完全一致

if(exp){}

if(exp1) exp2;

if(exp1) ...

else if(exp2) ...

else ...

例:

if(n1 + 3 < n2) n1 += 5;

if((n1 + 3 < n2) && (n2 > 8)) { n1 += 5; n2 += 3;}

if(n1 > 50) n2 = 1;

else if(n1 > 40) n2 = 2;

else n2 = 3;

for

语法与C, C++, C#语法完全一致

for( ;exp; ) exp2;

简单的自增或自减的for循环有特殊的优化,性能更优

for(int i = 0; i<count; ++i) exp2

for(int i = size; i>min; --i) exp2

while

语法与C, C++, C#语法完全一致

while(exp){...}

do while

语法与C, C++, C#语法完全一致

do{exp}while(exp2);

switch

支持整数,UTF8字符串,区段;

整数的switch, 与C, C++, C#语法一致;

字符串的switch, 与C#语法一致;

switch(str)

{

    case "a1":

        return 1;

    case "a2":

        return 2;

    case "a3":

        return 3;

    default:

        break;

}

区段switch是这里独创的,语法示例如下:

switch(n1)

{

    case [0, 100): // 如果 n1 >= 0 && n1 < 100

        return 1;

    case [150, 200): // 如果 n1 >= 150 && n1 < 200

        return 2;

    case [350, 400): // 如果 n1 >= 350 && n1 < 400

        return 3;

    default:

        break;

}

return

语法与C, C++, C#语法完全一致, 可以返回基础数据类型,自定义数据类型(class), 数组, map对象

this指针

例: this.m_value = 1; 或 this->m_value = 1;

this.func(...); 或 this->func(...);

做参数传递, 如:func(this, p1);

class

支持,语法与C++, C#语法完全一致

特性:

单继承与多继承 -- 支持

虚函数(多态) -- 支持

运行时转换 -- 支持

权限控制(public,private) -- 可支持, 目前全为public

属性方法(get,set) -- 可支持, 目前暂不支持

类成员变量支持定义时初始化,但只支持常数,这个初始化更高效。如:

class CTest

{

    int m_nValue = 10;

};

Delegate 委托

支持

Delegate

{

    public Delegate(AnyType obj, funcname(param1, param2, param3...)); // func_name 是 AnyType的成员函数

    public Delegate(AnyType obj, funcname, param1, param2, param3...);

    public void Call(); // 调用委托的方法

    public void SetParam(int nIndex, AnyType param); // 修改委托函数的第N个参数

}

创建方式

Delegate ptr = new Delegate(obj, func_name(param1, param2, param3, ...)); // 方式1

Delegate ptr = new Delegate(obj, func_name, param1, param2, param3, ...); // 方式2

ptr.Call(); // 启动委托函数的调用

反射

不支持严格意义上的反射,但支持Serialize类序列化一个类, 这个主要用于网络消息传输。

说明:这个序列化不支持版本兼容,是一个二进制流的有序读写,所以不要用这个来做持久化。

当然了,你也可以自己负责版本兼容的代码。

XML读写

目前对XML的读取是比较友好的,只需要一行代码,就可以将XML读取对应的数据结构中。

扩展了XML的功能,比C#都还要好用,真的,你用了就会喜欢它的。

扩展特性:

支持List的读写,支持自定义的class类型的List

支持map的读写,支持自定义的class类型的map

数组使用 value 关键字读取属性

map使用 key, value 关键字读取key与value

只需要在自定义的类成员变量前面添加[XmlElementAttribute]标签就可以了

XML代码与配置示例

Json读写

支持Json的读写,接口在os类中

public static bool ReadJson<_Ty>(_Ty pJsonRoot, StringA szJson)

public static StringA WriteJson<_Ty>(_Ty pJsonRoot)

例:

bool bSuc = os.ReadJson(msg, szJson);

inline

支持C++关键字inline, 标记inline的函数,调用时会内嵌到调用处,可以省去函数调用的开销,是优化的神器

好处:减少函数调用开销,提升性能

坏处:会增加代码长度,字节码变大

当然了,如果函数很简单,增加的长度可以忽略不计。

构造函数不支持 inline

递归函数,调用深度超过6层,就执行普通调用,不再内联, 所以递归就不要使用inline了。

全局变量

在类外声明的,目前都是全局变量,支持跨文件访问。

不需要static声明。

typedef

与C, C++语法一致, 但比C++灵活。为什么?因为可以不分顺序,可以乱序啊。

示例:

typedef int64 long

typedef map<int, CStringA> ID2Name;

typedef StringA CStringA; // CStringA 这个在ID2Name后声明

typedef map<int, ID2Name> IDArray; // 这个是错误的声明,因为目前map的key, value不支持模板

class A{ ID2Name id2Name;};

typedef map<int, A> IDArray;// 这个是合法的

enum 枚举

支持全局的 enum 与类内 enum, enum 的语法与C#一致

示例:

enum NUMB_VALUE{ NUMB1 = 1, NUMB2, NUMB3 = NUMB1 + 10, NUMB4};

int n1 = NUMB_VALUE.NUMB1;

class CTest

{

enum { NUMB1, NUMB2, NUMB3 };

};

const 常量

const 常量可以是类外声明,也可以是类内声明

支持const常量,支持 const常量的运算, const常量的引用不分顺序,可以是乱序的

class CTest

{

const int NUMB_MAX = NUMB1;

};

const int NUMB1 = NUMB2 + 10;

const int NUMB2 = NUMB3 + 10;

const int NUMB3 = 100;

const StringA TEST_STR1 = TEST_STR2 + "ABC"; // 编译时合并成一个字符串 "CC_ABC"

const StringA TEST_STR2 = "CC_";

const 字段会有额外的编译优化,请尽量使用

static_cast 强制转换

仅C基础数据类型支持强转, 大部分情况并不需要强制转换, 因为数据类型都是自动转换的

int64 i = 999999999999;

int k = (int)i + 10; // 等价于 int k = i + 10;

StringA str = (StringA)i + "__test"; // 等价于 str = i + "__test";

尽量不要强制转换,这有可能会导致额外的指令, 从而降低性能

注意:强制转换使用(), 并不是staic_cast

图形对象的扩展

支持以下图形对象

Vector2, Vector3, Vector4, Plane, Matrix, BoundBox, Ray, Bounds, Sphere, IntRect, Rect, Color, Color32, Bezier2D, Bezier3D, Quaternion

接口文档

IEnumerator/FCEnumerator 协程

因为与C#中IEnumerator名字冲突,也可以用FCEnumerator来替代

class IEnumerator // 这个类似于Delegate

{

    // 功能:启动协程

    public void Start();

    // 功能:停止协程;

    public void Stop();

    // 功能:唤醒wait的协程

    public void Wakeup();

    以下是兼容C#的接口,因为C#不能有全局函数

    public static FCEnumerator StartCoroutine(Object obj, param Object []params);

    public static FCEnumerator StartCoroutine(FCEnumerator ins);

    public static FCEnumerator StopCoroutine(FCEnumerator ins);

    按函数名停止协程,szFuncName必须是字符串常量

    public static FCEnumerator StopCoroutine(StringA szFuncName);

    按类名与成员函数名停止协程,szClassName, szFuncName必须是字符串常量

    public static FCEnumerator StopCoroutine(StringA szClassName, StringA szFuncName);

    public static FCEnumerator StopAllCoroutine();

};

协程对象是IEnumerator, 基本功能与API与c#基本一样

协程启动接口StartCoroutine

IEnumerator StartCoroutine(obj, 函数名称(参数1, 参数2, 参数3, ..., 参数N));

启动一个协程方式1:

IEnumerator coroutine = new IEnumerator(target, 函数名称(参数1, 参数2, 参数3, ..., 参数N));

coroutine.Start();

启动一个协程方式2:

IEnumerator coroutine = StartCoroutine(target, 函数名称(参数1, 参数2, 参数3, ..., 参数N));

停止一个协程:

方法1:通过IEnumerator参数停止

StopCoroutine(coroutine);

方法2:通过成员函数名字停止

如果当前函数不是类的成员函数,就按全局函数名搜索

StopCoroutine(函数名);

方法3:通过类名 + 函数名的方式

如果指定类名,不存在,就默认是全局函数

StopCoroutine(类名, 类成员函数名);

停止所有的协程

StopAllCoroutine();

异步await

支持awit异步接口,语法参考C#的await

Unity中的导出插件会自动生成带Task返回值的wrap接口

如下接口:

public static Task LoadResource(string szName)

跨平台交互

其他平台需要调用脚本的接口,需要先将脚本内的类名或函数名添加export或internal标记

例:

export void main()

{

}

export class TestA

{

    export void Func()

    {

    }

    void HideFunc() // 这个没有export导出,不可以在其他平台调用

    {

    }

}

详细调用参考Demo

调试

目前已经实现的功能有:

(1), 远程调试(可以调试真机代码)

(2), 支持单步调试

(3), 支持条件断点(暂未实现)

(4), 支持运行时修改变量,内存数据

(5), 支持断住后,代码跳转的功能,可以在当前函数内任意位置跳转,像VC++调试器一样

(6), 可以运行时切换调试与非调试的功能,优化性能。

(7), 支持局部变量,全局变量,this成员变量的控制台显示与修改

系统广播

案例代码

你可以对全局函数或类的成员函数添加一个标签[Boardcast]

格式如:[Boardcast("GroupName",Level)]

GroupName是函数的分组的名字,Level是调用的先后顺序

如:[Boardcast("OnEnterGame",1000)]

利用这个功能,可以将不同模块的代码解耦,各个模块不需要互相引用

只需要调用System.Broadcast(分组名,参数1,参数2,...),就可以实现模块之间的通信

最大的好外,上层不需要再使用一个管理器去转发事件通知,也不需要维护这些对象的生命周期

返回主页
Clone this wiki locally