概述:脚本
Jason:游戏引擎的语境中,脚本语言是高级、相对容易使用的编程语言,供用户方便地使用引擎常用的功能。
1.两种脚本语言
- 数据定义语言(data-difinition language):
数据定义语言的主要功能在于让用户创建及填充数据结构供引擎读取。这些语言通常是声明式的。
- 运行时脚本语言(runtime scripting language):
运行时脚本语言在运行时的引擎上下文执行。这些语言通常用于扩展或定制引擎游戏对象模型或者其他引擎系统的硬编码功能。
2.程序语言特性
游戏脚本语言的特性:
- 游戏脚本语言通常是直译式而非编译式的。(Cre:解释型语言)
- 轻量化。多数游戏脚本语言是轻量化的。虚拟机简单,内存消耗少。
- 支持快速迭代。修改原生引擎代码时,必须重新编译程序。但是脚本语言可以快速看到修改结果,有的甚至不需要重启游戏。
- 方便易用。
3.常见脚本语言
一些常见的脚本语言:
- QuakeC。雷神之锤的脚本语言。
- UnrealScript。虚幻引擎的脚本语言,基于C++语法风格。
- Lua。著名且流行的脚本语言,很容易整合至应用程序,包括游戏引擎。
- Python。过程式、面向对象、动态类型脚本语言。和Lua相似,也常作为游戏脚本语言。
4.脚本所需架构
- 回调脚本:
这种架构下一些小功能通常实现为钩子函数(hool function),或者称为回调(callback)。都是指用户提供一个函数供引擎调用。钩子可以用原生语言也可以脚本语言编写。
- 脚本定义新的游戏对象类型:
这种架构支持从一个原生语言编写的类派生一个由脚本语言编写的类(继承),还可以把脚本类的实例绑定到原生游戏对象(聚合)。
- 组件/属性脚本:
在基于组件或者基于属性的游戏对象模型中,可以用脚本创建组件或者属性对象。
- 脚本驱动的引擎系统:
脚本可能驱动整个引擎系统,游戏对象模型完全由脚本编写,仅当需要一些底层引擎组件时才调用原生引擎代码。
- 脚本驱动的游戏:
有些游戏引擎完全颠倒原生语言和脚本语言的关系。这些引擎中脚本语言才是主体,原生引擎代码仅作为程序库,用来调用一些高速的引擎部分。
5.脚语言的功能
Jason:脚本语言的功能主要是通过修改定制游戏对象模型来实现游戏性功能。
对原生编程语言的接口:
Jason:运行时脚本语言的虚拟机通常是嵌入游戏引擎中的。引擎启动虚拟机,需要时执行代码,并管理脚本的执行情况。执行的单位根据引擎和语言有所不同。
Jason:在脚本语言和原生代码之间最好容许双向通信,即脚本中可以调用原生代码。
Jason:在脚本中调用原生代码最基本的实现方法,是容许一些脚本函数用原生语言去实现而不是脚本语言。脚本调用某函数时,虚拟机负责查找对应原生函数的地址并调用它。(Cre:函数绑定?)
游戏对象句柄:
Jason:脚本函数通常要与游戏对象互动,而游戏中的对象通常是由引擎原生代码实现的。原生语言的指针和引用未必能用于脚本语言,例如有些脚本语言可能完全不支持指针。要传递对象引用,一个方法是在脚本中以数值型句柄来引用对象,脚本对象可能由引擎传递过来,或者通过其他一些查询取得。
Jason:脚本能把句柄作为参数来调用原生函数,来对对象进行一些操作。原生语言方面,句柄会被转换为指向原生对象的指针,然后处理该对象。
Cre:将Mono嵌入C++原生语言,C++的对象指针可以映射到C#的IntPtr类型。
Jason:数值型句柄的优点是简单,但是数值型句柄不够直观,另一个选择是使用对象的名称字符串或者字符串散列符,前提是脚本语言支持字符串转换为字符串散列标识符。
多线程:
Jason:并行执行多个脚本的能力一般是很有用的,特别对于现今高度并行的硬件架构而已尤其重要。多数脚本系统通过合作式多任务来提供并行性。这是指脚本会一直执行,直至他主动交出控制权。相反,抢占式多任务可以任意时候中断正在执行的脚本,令其他脚本得以执行。
(END)