如何将代码块存储在变量中,并在需要时调用它并获取其返回值



我正在Smalltalk中进行一次小的文本冒险。它由";屏幕";其中包括他们的文本和其他屏幕的选择。既然我希望游戏是动态的,我也希望包含分支。例如,如果玩家在铁匠铺,想买一把斧头,玩家会立即去屏幕检查玩家是否有足够的钱,并据此跳到另外两个屏幕中的一个。

我已经在工作了:屏幕(名为Place的类(有一个列表,其中第一项是函数,下面的项是参数。然而,我用一种非常丑陋的方式完成了它:第一项是一个字符串,然后用一个大的"进行比较;动作";方法,所以它看起来像这样:
游戏数据方法:

blacksmith := Place new.
blacksmith choiceText: 'I would like an axe.';
blacksmith action add: 'money'; add: 20; add: blacksmith_good; add: blacksmith_bad.

操作方法:(currentScreen也是一个Place;该类还包含一个执行实际决策的BranchMoney方法(

(currentScreen action at: 1) = 'money'
ifTrue: [
currentScreen := (currentScreen BranchMoney)
]

这显然不理想,我想通过这样做来压缩它:
游戏数据方法:

blacksmith action add: [blacksmith BranchMoney]; add: 20; add: blacksmith_good; add: blacksmith_bad.

动作方法:

currentScreen := (currentScreen action at: 1)

这样游戏就可以直接按照我想要的方法进行,而不是字符串检查

然而,它似乎不起作用——我尝试过对代码进行不同的更改,问题似乎是currentScreen := (currentScreen action at: 1)行只是用代码块内容替换currentScreen的内容——它没有计算块的内容,也没有使用Place类型的结果值。

我曾尝试在游戏数据方法中使用圆括号,这会抛出一个列表越界异常,因为它试图在添加其他参数之前立即计算表达式。将游戏数据方法中的第一个项目名称更改为currentScreen BranchMoney似乎没有什么区别
我还尝试在游戏数据方法中添加一个return,比如:blacksmith action add: [^blacksmith BranchMoney],这样它就有一个值要返回,没有运气。在action方法中执行类似currentScreen := [^currentScreen action at: 1]的操作也不起作用
对于黑暗中的一些镜头,我尝试了ExternalProcedurecallcall:方法,但也失败了。

在Smalltalk中,每个块都是一个常规对象,您可以像存储和检索任何其他对象一样存储和检索:

b := [self doSomething]

b中存储该块(与b := 'Hello'b中存储字符串一样(。我认为您缺少的是#value消息。要执行块,请执行以下

b value   "execute self doSomething and answer with the result"

如果您的块有一个参数,请使用#value:而不是

b := [:arg | self doSomethingWith: arg]

稍后在上

b value: 17   "execute the block passing 17 as the argument"

(对于两个参数,使用#value:value:,对于三个#value:value:value:和许多#valueWithArguments:。(

然而,请注意,这种使用参数块和数组的方法看起来并不优雅(甚至不方便(。然而,为了帮助您找到更好的选择,我们需要了解更多关于您的游戏的信息。所以,去看看#value(和朋友们(是否让你进步了一点,然后可以自由地回到这里提出你的下一个问题。经过几次迭代,我们可以引导您走向更清晰的路线。


示例

b := [:m | m < 20 ifTrue: ['bad'] ifFalse: ['good']].

将产生

b value: 15 "==> 'bad'"
b value: 25 "==> 'good'"

最新更新