《GDScript:协程(Coroutine)(一)概念和使用范例 》中介绍了GDScript中协程的概念和简单用法。写完之后总感觉GDScript的协程有哪里不对劲儿,刚才终于琢磨过来“是它的语法形式”。
分析GDScript之前先看一下C#的协程
C#的协程定义和调用都有多种重载,下面以非反射的一种重载为例:
协程函数定义
IEnumerator CoroutineFunction()
{
...
yield return 0;
...
yield return 0;
...
yield return 0;
}
调用协程
Coroutine c = StartCoroutine(CoroutineFunction());
...
StopCoroutine(Coroutine);
从上面代码可以看到C#协程有以下特点:
- 定义了
yield return
组合关键字,标志这种返回的“特殊性”,并体现了这是语法层次的支持 - 严格定义了协程函数的返回值类型即迭代器接口类型
IEnumerator
- 使用
Coroutine
存储协程的引用,并使用StartCoroutine
和StopCoroutine
开关协程并返回协程的引用。
总的来说,C#协程的语法形式是非常严谨的,和我们对函数的原有理解没什么冲突
下面看一下GDScript的协程就“粗糙”很多,甚至有点“莫名其妙”
func coroutine_function():
print("Coroutine:Hello")
yield()
print("Coroutine:Coroutine")
func _ready():
var y = coroutine_function()
print("Hello")
y.resume()
- 没有定义新的关键字,用了一个
yield()
函数 coroutine_function
的返回值是什么? 如果说没有返回值,在_ready
中它却按照函数返回的格式给y
赋了一个GDScriptFunctionState
对象 如果说有返回值,那按照3.1的GDScript语法给函数加一个返回类型限制会直接报错func coroutine_function() -> GDScriptFunctionState:
如果给yield()
前面加个return
,那么y.resume()
以后print("Coroutine:Coroutine")
也不会再执行了,毕竟return
是退出函数的终极指令。
所以,要在语法形式上较真的话,GDScript的协程设计太粗糙了
然而
我却认为这是Godot之父Juan Linietsky的大智慧之所在。语言的设计方面,不为了追求形式上严谨和完美,徒增语法概念的复杂度以及引擎实现的难度。毕竟游戏引擎和脚本语言只是游戏开发的工具,如果这种“简单粗暴”能够让使用者和开发者双方都轻松,何乐而不为呢?正所谓“退一步海阔天空”。在双U横行世界,很多大牌引擎都横尸遍野的今天,Juan Linietsky和他的几个小伙伴,能够开发出恒快2D/3D,且如此功能齐全,使用顺手,体积小巧并被大家津津乐道的Godot,这种实用至上的设计哲学是功不可没的。