我正在制作一个基于文本的游戏,需要一个可以在任何文本条目中提取的应用程序范围的命令行。我的计划是让命令包含在一个模块中,并执行command(),然后允许用户输入一个命令(或获取一个列表)然后运行(包含在同一个模块中)。这不起作用,因为我需要一种方法来返回用户所在的位置。无论如何返回到用户进入命令模式之前的位置,还是有更好的方法来做到这一点?
这是我的想法:
import commands
def something():
print "a question"
action = raw_input("> ")
if action == "command":
commands.commands()
elif "something else" in action:
do something
else:
error.error(1)
something()
然后转到commands.py:
def commands():
print "Enter a command, help for a list, blah blah blah."
command = raw_input("$ ")
if command == "bag":
bag()
elif command == "other":
other()
def bag():
print "Action listing things in bag"
问题是返回用户离开的地方。
答案 0 :(得分:2)
你需要的是一个主要的游戏循环:
while game.is_running:
command = get_user_input()
user_do(command)
update_world()
只要while
为game.is_running
,这将在True
循环内重复三行代码。首先,您获得用户输入。接下来,你采取行动。最后,您可以执行游戏所需的任何其他更新,例如移动或产生怪物。此时,它会循环返回并要求用户输入另一个命令。
更新:这是一个有效的例子:
# In commands.py:
def bag():
print 'bag'
def other():
print 'other'
def unrecognized():
print 'unknown command'
# In main.py:
import commands
def user_input():
print 'a question'
return raw_input('>')
def user_do(command):
# get the matching command out of commands, or pass back
# the unrecognized function if it's not found
action = getattr(commands, command, commands.unrecognized)
action()
is_running = True
while is_running:
command = user_input()
if command == 'quit':
is_running = False
else:
user_do(command)
在这个例子中,我已经作弊,并且依赖于用户输入命令与要调用的函数的名称相同。在user_do
中,getattr
调用将用户输入的字符串与command
模块的内容进行比较,返回相同名称的函数(如果存在)或回退函数{{ 1}}如果没有。 unrecognized
现在将保留命令功能或action
。
如果您不希望将用户命令与实际函数本身紧密绑定,则可以使用unrecognized
作为分支构造(或 dispatch )而不是很多dict
陈述:
if / elif / else
在此示例中,我们不是在# Modified main.py
import commands
COMMAND_DISPATCH = {
'bag': commands.bag,
'sack': commands.bag,
'other': commands.other,
# ...
}
# ...
def user_do(command):
action = COMMAND_DISPATCH.get(command, commands.unrecognized)
action()
模块中查找函数,而是在commands
中查找它们。
还有一点建议:很快你就会想要将用户输入解析为不止一个命令。对于此示例,假设您希望能够接受“command ...”形式的输入。您可以扩展COMMAND_DISPATCH
功能来处理这个问题:
user_input
因此,如果您输入'foo bar baz',这将返回元组def user_input():
print 'a question'
user_input = raw_input('>').split(' ')
command = user_input[0]
arguments = user_input[1:]
return command, arguments
。接下来我们更新主循环来处理参数。
('foo', ['bar', 'baz'])
然后确保我们将它们传递给命令:
while is_running:
# use tuple unpacking to split into command, argument pairs
command, arguments = user_input()
if command == 'quit':
is_running = False
else:
user_do(command, arguments)
最后,我们修改接受和处理参数的命令:
def user_do(command, arguments):
action = COMMAND_DISPATCH.get(command, commands.unrecognized)
action(arguments)
对于文字冒险,你需要一个更实质的解析器,它可以处理def bag(arguments):
for argument in arguments:
print 'bagged ', argument
,command object
,甚至可能command object preposition subject
。
答案 1 :(得分:0)
你应该研究“python有限状态机”。它几乎就是你想要的。
什么是状态机?
对状态机的过于准确的描述是它是一个 有向图,由一组节点和一组相应的组成 过渡功能机器通过响应系列“运行” 事件。每个事件都在转换函数的域中 属于“当前”节点,其中函数的范围是a 节点的子集。该函数返回“下一个”(也许是 相同的)节点。这些节点中的至少一个必须是最终状态。当一个 达到最终状态,机器停止。
何时使用状态机...
- 从初始状态开始。
- 阅读一行输入。
- 根据输入和当前状态,转换为新状态或根据当前状态处理该行。
醇>
类似于@MatthewTrevor在他的回答中建议的,你将有一个主循环,并将“状态”上下文传递给第一个入口点调用(start
或intro
或其他)。该调用可以改变状态上下文以指向其他内容。当控制再次返回主循环并检查状态时,它将运行新状态。