【问题标题】:Grab user input asynchronously and pass to an Event loop in python异步获取用户输入并传递给python中的事件循环
【发布时间】:2012-06-12 02:24:08
【问题描述】:

我正在构建一个单人 MUD,它基本上是一个基于文本的战斗游戏。它没有联网。

我不明白如何收集用户命令并将它们异步传递到我的事件循环中。玩家需要能够在游戏事件触发时随时输入命令。因此,使用 raw_input 暂停该过程是行不通的。我想我需要做一些类似 select.select 和使用线程的事情。

在下面的示例中,我有一个 userInputListener() 模型函数,我喜欢在其中接收命令,如果有输入,则将它们附加到命令 Que。

如果有事件循环如:

from threading import Timer
import time

#Main game loop, runs and outputs continuously
def gameLoop(tickrate):

    #Asynchronously get some user input and add it to a command que 
    commandQue.append(userInputListener())
    curCommand = commandQue(0)
    commandQue.pop(0)

    #Evaluate input of current command with regular expressions
    if re.match('move *', curCommand):
        movePlayer(curCommand)
    elif re.match('attack *', curCommand):
        attackMonster(curCommand)
    elif re.match('quit', curCommand):
        runGame.stop()
    #... etc    

    #Run various game functions...
    doStuff()

    #All Done with loop, sleep
    time.sleep(tickrate)

#Thread that runs the game loop
runGame = Timer(0.1, gameLoop(1))
runGame.start()

我如何获得我的用户输入?

或者更简单地说,谁能告诉我在另一个循环同时运行时存储用户输入的任何示例?如果我们能走到那一步,我可以弄清楚其余的。

【问题讨论】:

  • Twisted 是一个选项吗?
  • 您可能想尝试使用 PyGame 或 curses 来处理您的输入,而不是自己滚动。
  • MUD 不代表多用户地下城吗?无论如何,我同意@AndrewGorcester,避免重新发明轮子可能会更容易。

标签: python input event-loop mud


【解决方案1】:

您确实需要两个线程。一个负责主游戏循环,另一个负责处理用户输入。两者将通过Queue 进行通信。

您可以让您的主进程启动游戏循环线程,然后让它从用户那里获取一行文本并将其“放入”队列中(即在 runGame.start() 之后)。这可以很简单:

while not gameFinished:
    myQueue.put(raw_input()). 

游戏循环线程将简单地从队列中“获取”一行文本,并对其进行解释和执行。

Python 有一个线程安全的queue implementation,您可以使用它(包括一个非常基本的多线程使用示例,您可以将其用作指南)。

还有一个简单的命令行interperter 模块(cmd modulehere 是一个很好的实用概述),它也可能对这类项目有用。

【讨论】:

    【解决方案2】:

    我制作了一个 pygame hanoi-visualiser,它可以异步读取输入 here

    重要的几行是:

    #creates an input buffer for stdin 
    bufferLock=threading.Lock()
    inputBuffer=[]
    
    class StdinParser(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
        def run(self):
            global inputBuffer
            running = True
            while running:
                try:
                    instruction=raw_input()
                    bufferLock.acquire()
                    if inputBuffer == False:
                        running = False
                    else:
                        inputBuffer.insert(0,instruction)
                    bufferLock.release()
                except EOFError:
                    running = False
            pyglet.app.exit()
    
    def check_for_input(dt):
        bufferLock.acquire()
        if len(inputBuffer)>0:
            instruction = inputBuffer.pop()
            parseLine(instruction,board)
        bufferLock.release()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-18
      • 1970-01-01
      • 2015-03-31
      • 2013-02-10
      • 2020-12-08
      相关资源
      最近更新 更多