Python で単純なテキスト ベースのアドベンチャー ゲームを作成しています。ユーザーの操作に関係なく、約 2 分ごとに特定のプロセスが定期的に発生するようにしたいと考えています。例: NPC を部屋の中を移動させたり、人々に空腹や喉の渇きを与えたり、人々を回復させたり、戦闘中に戦闘を進行させたりします。現在、「raw_input」を使用してユーザーからコマンドを取得していますが、これは本質的にコードを一時停止します。ユーザーがそこに座って何も入力していない場合でも、どうすればゲームを進行させることができますか?
5 に答える
通常、この状況では、計算を行うバックグラウンド プロセスやスレッドは存在しないと思います。代わりに、ユーザーがなんらかの応答を入力すると、タイム デルタが実行され、入力間の経過時間に基づいて、プレイヤーが回復した量や戦闘イベントがどうなるかなどが計算されます。これは、コンソールの更新が必要ない場合です。ゲームがユーザーの応答を待っている間。
編集:または次のようなものを試してください:
import time
import sys
win32 = True
try:
from msvcrt import kbhit, getch
print "[+] Running on windows, using msvcrt."
except ImportError:
print "[+] Not running on windows, attempting unix-like."
win32 = False
import termios, fcntl, sys, os
import select
fd = sys.stdin.fileno()
oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
POLLTIME = 5
done = False
command = ""
while not done:
sys.stdout.write("\r")
print("Something happened (polling)%s" % (" " * command.__len__() ))
sys.stdout.write("Enter command: %s" % command)
sys.stdout.flush()
t = time.time()
if win32:
while time.time() - t < POLLTIME:
if kbhit():
c = getch()
if ord(c) < 127 and ord(c) > 31:
command += c
message = "\rEnter command: " + command
sys.stdout.write("\r%s" % message)
if "\r" == c:
if "quit\r" == command:
done = True
break
sys.stdout.write("\rThe command was: %s\n" % command)
command = ""
sys.stdout.write("\rEnter command: %s \b" %command)
elif "\b" == c:
command = command[:-1]
sys.stdout.write("\rEnter command: %s \b" %command)
sys.stdout.flush()
else:
while time.time() - t < POLLTIME:
try:
c = '\0'
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
c = sys.stdin.readline(1)
if ord(c) < 127 and ord(c) > 31:
command += c
message = "\rEnter command: " + command
sys.stdout.write("\r%s" % message)
if c == "\n":
if "quit" == command:
done = True
break
print("\rThe command was: %s" % command)
command = ""
message = "\rEnter command: " + command
sys.stdout.write("\r%s" % message)
if 127 == ord(c):
command = command[:-1]
sys.stdout.write("\rEnter command: %s \b" % command)
sys.stdout.flush()
except IOError:
pass
コードを一時停止せずにユーザー入力を読み取る方法があります。「非同期 I/O」または「ノンブロッキング I/O」と呼ばれます。これを行う 1 つの方法は、別のスレッドを作成してユーザーのリクエストをリッスンし、キューに入れてゲーム ループ内で処理することです。
この質問とその回答では、Python で非ブロッキング I/O を実行する方法について説明しています:非ブロッキング読み取り on a subprocess.PIPE in python
答えは -- コンソール用にリアルタイムで書かないことです! これをテキストベースで行いたい場合は、Tkinter に切り替えることをお勧めします。これにより、これらのことを個別に行うことができます。また、これらの定期的なイベント中にテキストを表示し、単純な .after() 呼び出しを使用してそれらを実行できます。
各入力の後に時間をサンプリングします (成功したコマンドに対してのみ行うか、オプションで無効なものを含めるかはあなた次第です)。
この時間を前のサンプルと比較し、ワールド ティック間隔で割ります。
ティック (
for npc in npcs: npc.move_to_adjacent_posn()
など) ごとに発生するアクティビティのリストを反復処理します。
別のスレッドを使用せずにこれを行う方法がわかりません(別のスレッドを使用するのは簡単です)。
しかし、ここでの私のポイントは次のとおりです。あなたのテキストベースの関数はイベント/コマンドベースのアプリケーションのように見えますか? つまり、ユーザーからのコマンド/イベントがこれ以上ない場合、クライアントの状態は変化しませんか? 時限関数で何を監視しようとしているのかはわかりませんが、アプリケーションがまだイベントベースでない場合、つまり、ユーザーが実行/送信する一連のイベントから状態を集約する場合は、アプリケーションをイベントにすることができます。ベースの場合、時限機能を取り除くことができます。その助けを願っています。