質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

2回答

2245閲覧

Pythonでゲームイベントを実行後、元の画面への戻し方がわかりません。(place_forget関数)

manabu.h

総合スコア0

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/06/17 12:03

編集2020/06/18 01:13

Pythonでゲームイベントを実行後、元の画面への戻し方がわかりません。(place_forget関数)

Pythonの入門書で、
下記のプログラミング(①→②→③の順に実行する)
を写経中に、
②の段階で詰まってしまいました。
間違っているところがわからず、2時間経ってしまったので
どなたかコードに変なところがあればご指摘いただけると助かります。
よろしくおねがいします。

※該当書籍「12歳からはじめる ゼロからの Pythonゲームプログラミング教室」
サンプルコード(http://www.rutles.net/download/463/)
→この中の「chap7.py」と「chap7fight.py」のコードを使用します。

自分が詰まっているのはその途中過程においてですが、
サンプルには完成型のコードしかないためコード比較がしづらい状態です…

実行したいプログラミングの内容

①戦闘画面を前面に制作し、
デフォルトのマップ上でモンスターに遭遇するまでは、
戦闘画面は非表示にさせる。(これはできた)

②戦闘画面を表示して、「勝った」「負けた」のボタンのうち
「勝った」を押すと、戦闘画面を非表示にして
元のマップ上に戻る。

(この戦闘画面を非表示にすることができない)

③戦闘画面を表示して、「勝った」「負けた」のボタンのうち
「負けた」を押すとバッドエンドの別画面を表示させる。(これはできた)

※メインのコード(デフォルトのマップ画面)に、サブコード(戦闘画面)を読み込ませて制作するものです。

 ### 不審な挙動
②実行時、戦闘画面で「勝った」ボタンをクリックしたあとに
フリーズしてしまいます。
試しにtabキーを押してみたら
戦闘画面の横に、デフォルトMAP上の移動キーが表示され、
クリックしたらデフォルトMAPの画面に戻りました。
「勝った」ボタンのクリックだけで、デフォルトMAP画面に戻りたいです…イメージ説明
イメージ説明
イメージ説明
イメージ説明

機能して欲しいコード

self.dialog.place_forget()

エラーメッセージ

エラーメッセージはありませんでしたが、 意図が反映されていません。

呼び出し側のソースコード(デフォルトMAP)

import tkinter import chap7fight #マップの描画 def draw_map(): for y in range(0, MAX_HEIGHT): for x in range(0, MAX_WIDTH): p = map_data[y][x] if p >= 5: p =5 canvas.create_image(x*62+31, y*62+31, image=images[p]) #主人公表示 canvas.create_image(brave_x*62+31, brave_y*62+31,image=images[4], tag="brave") #移動先のチェック def check_move(x,y): global brave_x, brave_y, flag_key if x >= 0 and x <MAX_WIDTH and y >= 0 and y < MAX_HEIGHT: p = map_data[y][x] if p == 1: return elif p == 3: flag_key = True map_data[y][x] = 0 canvas.delete("all") draw_map() elif p == 2: if flag_key == True: ending() else: return elif p >= 5: fightmanager.fight_start(map_data, x, y) brave_x = x brave_y = y draw_map() # canvas.coords("brave", brave_x*62+31, brave_y*62+31) #上ボタンが押された def click_button_up(): check_move(brave_x, brave_y-1) #下ボタンが押された def click_button_down(): check_move(brave_x, brave_y+1) #左ボタンが押された def click_button_left(): check_move(brave_x-1, brave_y) #右ボタンが押された def click_button_right(): check_move(brave_x+1, brave_y) #エンディング表示 def ending(): canvas.delete("all") canvas.create_rectangle(0, 0, 620, 434, fill="black") canvas.create_text(300, 200, fill="white", font=("MS ゴシック", 15), text=""" ゴールおめでとう。 だが、君の戦いはまだ始まったばかりだ。 ……つづく?""") #ボタンを無効化 button_up["state"] = "disabled" button_down["state"] = "disabled" button_left["state"] = "disabled" button_right["state"] = "disabled" #ウインドウ作成 root = tkinter.Tk() root.title("ダンジョン&パイソン") root.minsize(840, 454) root.option_add("*font",["メイリオ", 14]) #キャンバス作成 canvas = tkinter.Canvas(width=620, height="434") canvas.place(x =10, y =10) canvas.create_rectangle(0, 0, 620, 434, fill="gray") #ボタンを配置 button_up = tkinter.Button(text="↑") button_up.place(x=720, y=150) button_up["command"] = click_button_up button_down = tkinter.Button(text="↓") button_down.place(x=720, y=210) button_down["command"] = click_button_down button_left = tkinter.Button(text="←") button_left.place(x=660, y=180) button_left["command"] = click_button_left button_right = tkinter.Button(text="→") button_right.place(x=780, y=180) button_right["command"] = click_button_right #画像データを読み込み images = [tkinter.PhotoImage(file="12saipython/img6/chap6-mapfield.png"), tkinter.PhotoImage(file="12saipython/img6/chap6-mapwall.png"), tkinter.PhotoImage(file="12saipython/img6/chap6-mapgoal.png"), tkinter.PhotoImage(file="12saipython/img6/chap6-mapkey.png"), tkinter.PhotoImage(file="12saipython/img6/chap6-mapman.png"), tkinter.PhotoImage(file="12saipython/img6/chap7-mapmonster.png")] #マップデータ MAX_WIDTH = 10 MAX_HEIGHT = 7 map_data = [[1, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 1, 2, 0, 6, 1, 3, 1], [1, 1, 0, 1, 1, 1, 0, 1, 0, 1], [1, 0, 0, 5, 0, 0, 0, 1, 0, 1], [1, 0, 1, 1, 1, 1, 1, 1, 6, 1], [1, 0, 6, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] #主人公の位置 brave_x = 1 brave_y = 0 #鍵取得フラグ flag_key = False #戦闘画面の準備 fightmanager = chap7fight.FightManager() draw_map() root.mainloop()

サブのソースコード(戦闘画面)

import

1 2class FightManager: 3 #戦闘画面 4 def __init__(self): 5 self.dialog = tkinter.Frame(width=820, height=434) 6 self.dialog.place(x=10, y=10) 7 canvas = tkinter.Canvas(self.dialog, width=820, height=434) 8 canvas.place(x=0, y=0) 9 canvas.create_rectangle(0, 0, 620, 434, fill="black") 10 #ボタン作成 11 winbutton = tkinter.Button(self.dialog, text="勝った") 12 winbutton.place(x=180, y=340) 13 #このコマンド↓がうまく作動してくれません。 14 winbutton["command"] = self.fight_win 15 losebutton = tkinter.Button(self.dialog, text="負けた") 16 losebutton.place(x=320, y=340) 17 losebutton["command"] = self.fight_lose 18 #モンスターに遭遇するまでは非表示にする 19 self.dialog.place_forget() 20 21 #モンスターと遭遇、戦闘画面を表示 22 def fight_start(self, map_data, x, y): 23 self.dialog.place(x=10, y=10) 24 self.map_data = map_data 25 self.brave_x = x 26 self.brave_y = y 27 28 #「勝った」を選択 29 def fight_win(self): 30 self.map_data[self.brave_y][self.brave_x] = 0 31 #このコマンド↓がうまく作動してくれません。 32 self.dialog.place_forget() 33 34 #「負けた」を選択 35 def fight_lose(self): 36 canvas = tkinter.Canvas(self.dialog, width=820, height=434) 37 canvas.place(x=0, y=0) 38 canvas.create_rectangle(0, 0, 620, 434, fill="red") 39 canvas.create_text(300, 200, fill="white", font=("MS ゴシック", 15), 40 text="""勇者は負けてしまった。 41 もう一度出直そう。""") 42

使用ツールなど

環境:Mac OSX
エディタ:Visual Studio Code
Python3.6.5

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

エラーメッセージはありませんでしたが、
意図が反映されていません。

エラーは本当に出てませんか?

意図的にエラーを起こして、開発環境でエラーが出ることを確認してみて下さい。
例えば、デバッグ環境での実行でない場合、エラー出力が何処にも表示されない場合があります。

エラー表示が正しく出ることを確認してから、
print文を前後に入れる等して、該当部分のコードが実行されているか確認してみましょう。


  • コードの一部を検索して、書籍のサイトからコードサンプルと画像をダウンロード
  • 質問文のコードに差し替えて実行してみたところ、fight_startメソッドで引数不一致のエラーが出ました

diff

1- def fight_start(self, map_data, x, y): 2+ def fight_start(self, map_data, x, y, brave):

修正により、place_forget() の動作を確認。

出来れば、書籍情報や動作可能で問題を再現できるソースコードの掲載をお願いします。

検索して書籍のサイトとサンプルコードが出てきたので手がかりを得られましたが、
動作確認が出来ないコード&呼び出し側のコードは不明だと、
質問に記載されてる情報だけでは、問題の特定は不可能です。


間違っているところがわからず、2時間経ってしまったので

写経で詰まった場合、
"Diff" という2つの文書を比較して差分を表示してくれるツールがあるので、
書籍のサポートサイト等からソースコードを入手して、自分の書いたコードと比較してみると良いですよ。

投稿2020/06/17 19:28

teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

manabu.h

2020/06/18 00:32

ご丁寧にありがとうございます。 いろいろと不足部分があり、失礼いたしました。 まず、書籍名と、呼び出し側のコードを追記します。 エラーの確認はVSCodeのターミナルで、Pythonを動かしながら確認していますが、 今のところ、呼び出し側、呼び出される側、双方のコードでエラーメッセージは出てきてくれません… わざと他の場所でエラーを発生させると、しっかりエラーメッセージは出てきてくれるのですが… Diffを知りませんでした、助かります! ただ、サンプルコードには完成型しか無く、 ご指摘の不一致部分に関しては、後のページで追加をする予定のコードでした… 新しくわかったこととして、 戦闘画面で「勝った」ボタンを押したあと、 フリーズしてしまうのですが(画面が元に戻らない状態) その状態でtabキーを押すと デフォルトMAP上の移動ボタンが画面横に現れることがわかりました… クリックするとデフォルトMAP上の主人公が動いていて 画面が戻るというおかしな挙動を見せています。
teamikl

2020/06/18 07:30 編集

なるほど、作成途中のコードで、引数自体はこの時点では問題なかったのですね。 win10/python3.6,3.8.3 では問題の現象を確認できませんでした。 ちなみに、完成型のコードでは問題なく動くのでしょうか? 確認ですが、手元のコードと、実際に実行されてるコードで相違などはありませんか? (VSCodeの設定で他のファイルが実行されている。や、 作業中の他のファイルが同じディレクトリ内にある場合等) # 確認方法: chap7.py で import os print(os.path.abspath(__file__)) # 訂正: sys.argv -> sys.argv[0] or __file__ import chap7fight print(chap7fight) # モジュールのPATHを確認
teamikl

2020/06/18 10:17

VSCodeでの実行はどのように行ってますか?(具体的な手順) デバッグでステップ実行になった場合等で、GUIがフリーズすることがありますが、 コードが中断されてGUIの更新が行われないというのは、 (デバッグとしては)正常な動作なこともあります。 ボタンクリック時のイベント内で問題が起こった場合、 その関数の処理が終わりmainloop()に処理が戻らないとGUIは動きません。
teamikl

2020/06/18 10:29

追加で確認事項。試しにVisual Studio Code 以外の ターミナルから コマンドを打ってプログラムを実行して動作を確認できますか?
guest

0

元の構造

- root (Tk) - self.dialog (Frame) <- 親ウィジェットが省略されている - canvas (Canvas) - winbutton (Button) - losebutton (Button)

変更点

- root (Tk) - self.dialog (Frame) <- 明示的に親ウィジェットを指定 - canvas (Canvas) - winbutton (Button) <- キャンバス上に乗せる (place -> canvas.create_window) - losebutton (Button)

と変更してみました。確認用のコードですが、
以下のコードで問題(place_forgetが機能しない)は再現するでしょうか?

import tkinter class FightManager: def __init__(self, master): self.dialog = tkinter.Frame(master, width=820, height=434) # テスト用に追加。 showbutton = tkinter.Button(master, text="再表示") showbutton["command"] = lambda: self.dialog.place(x=10, y=10) showbutton.pack() canvas = tkinter.Canvas(self.dialog, width=820, height=434) canvas.place(x=0, y=0) canvas.create_rectangle(0, 0, 620, 434, fill="black") winbutton = tkinter.Button(canvas, text="勝った") winbutton["command"] = self.fight_win losebutton = tkinter.Button(canvas, text="負けた") losebutton["command"] = self.fight_lose # キャンバスにウィジェットを乗せる場合 -> canvas.create_window # place() との違いは、キャンバスがスクロールする場合でも、 # キャンバス上の座標で表示されます。 canvas.create_window(180, 340, window=winbutton) canvas.create_window(320, 340, window=losebutton) self.dialog.place(x=10, y=10) def fight_win(self): self.dialog.place_forget() def fight_lose(self): pass if __name__ == '__main__': root = tkinter.Tk() root.geometry("400x400") manager = FightManager(root) root.mainloop()

デバッグの手段

まずは、コメントに書いた点を確認してみて下さい。

  • エラーが正常に出力されることを確かめる
  • place_forgetが呼ばれていることを確認する。(前後に print 文を追加する等して)

現状では、他のエラーで止まってるのか、
place_forget()自体が機能しない問題なのかの区別が付きません。
(コードの問題なのか、環境問題なのかの区別)

サブのソースコード(戦闘画面)もimport tkinter がありませんが、第三者の視点からは
省略されたコードが import 文だけなのか、他にもコードが省略されてるのかが解りません。

可能なら、画像など余分なものも含まず(置き換える等して)
問題が再現できる最小限のコードを提示すると良いです。
画像がないと実行できない → 試してくれる人も少なくなったりします。

投稿2020/06/18 10:24

teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問