0

我正在制作一个基于文本的游戏,并且需要一个能够在任何文本输入处被拉出的应用程序范围的命令行。我的计划是将命令包含在一个模块中,然后执行 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"

问题是返回用户离开的地方。

4

2 回答 2

2

你需要的是一个主游戏循环:

while game.is_running:
    command = get_user_input()
    user_do(command)
    update_world()

while只要game.is_runningis ,这将重复循环内的三行代码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模块的内容进行比较,如果存在则返回同名函数,unrecognized如果不存在则返回后备函数。action现在将保持命令功能或unrecognized.

如果您不想让用户命令与实际函数本身如此紧密地绑定,则可以使用 adict作为分支构造(或dispatch)而不是使用大量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_DISPATCH

还有一点建议:很快你就会想把用户输入解析成不止一个命令。对于此示例,假设您希望能够接受“command ...”形式的输入。您可以扩展该user_input功能以解决此问题:

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”,这将返回元组('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,甚至可能command adjective object ....

于 2012-09-12T02:40:03.913 回答
0

您应该研究“python 有限状态机”。这几乎正​​是您想要的。

什么是状态机?

状态机的一个过于准确的描述是它是一个有向图,由一组节点和一组相应的转换函数组成。机器通过响应一系列事件来“运行”。每个事件都在属于“当前”节点的转换函数的域中,其中函数的范围是节点的子集。该函数返回“下一个”(可能是相同的)节点。这些节点中至少有一个必须是结束状态。当达到结束状态时,机器停止。

何时使用状态机...

  1. 从初始状态开始。
  2. 读取一行输入。
  3. 根据输入和当前状态,要么转换到新状态,要么根据当前状态处理行。

与@MatthewTrevor 在他的回答中建议的类似,您将拥有一个主循环,并将“状态”上下文传递给第一个入口点调用(startintro其他任何东西)。该调用可以更改状态上下文以指向其他内容。当控制再次回到主循环并检查状态时,它将运行新状态。

于 2012-09-12T16:55:32.623 回答