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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

1477閲覧

SDL::KeyDown 文字を読みこまない

yusuke.

総合スコア66

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2016/09/03 01:24

編集2016/09/03 01:43

いつもお世話になっております。
今回クイズを作っているのですが、押された文字を読み込むことができません。
スペースを押すと、問題が表示されるところまでは、期待通りの動作をしてくれます。しかし、数字を押してもそのままスルーされて毎回a の値が0(入力した数字0 )となっています。また、なにも押さなくても aの値が0とされ、そのまま正解かどうかの判定をして、繰り返しています。
簡単に言うと、入力した文字を読み込む以外はすべて期待通りの動作をしています。
もしかしたらwhileを使いまくっていたので、そこがおかしいのかもしれません。

ruby

1 def start 2 @font.put(@screen2,"今から問題が出てきます。問題によって、スコアが異なります。",50,30,0,0,0) 3 @font.put(@screen2,"正解だと思う選択肢の番号のキーボードを押してください。",50,70,0,0,0) 4 @font.put(@screen2,"始めるにはスペースキーを押してください。",50,120,0,0,0) 5 refresh 6 while true do 7 while event = SDL::Event2.poll do 8 case event 9 when SDL::Event2::Quit 10 exit 11 when SDL::Event2::KeyDown 12 if event.sym == SDL::Key::SPACE then 13 kuizustart 14 break 15 end 16 end 17 end 18 end 19end 20 21def kuizustart 22keycount = 0 23 while true do 24 drawBack 25 mondai 26 kotaeawase 27 sleep 2 28 keycount = keycount + 1 29 if keycount == 10 30 gameOver 31 sleep 5 32 end 33 end 34end 35 36 37def kotaeawase 38 @font.put(@screen2,"数字を入力してください",50,220,0,0,0) 39 refresh 40 while event = SDL::Event2.poll do 41 SDL::Event2.wait 42 case event 43 when SDL::Event2::Quit 44 exit 45 when SDL::Event2::KeyDown 46 if event.sym == SDL::Key::K1 or event.sym == SDL::Key::KP1 47 a = 1 48 end 49 if event.sym == SDL::Key::K2 or event.sym ==SDL::Key::KP2 50 a = 2 51 end 52 if event.sym == SDL::Key::K3 or event.sym == SDL::Key::KP3 53 a = 3 54 end 55 if event.sym == SDL::Key::K4 or event.sym ==SDL::Key::KP4 56 a = 4 57 end 58 if event.sym == SDL::Key::K5 or event.sym == SDL::Key::KP5 59 a = 5 60 else 61 next 62 puts "0,1,2,3,4,5のどれかを入力してください。" 63 end 64 end 65 end 66 @font.put(@screen2,"入力した数字",50,250,0,0,0) 67 @font2.draw_solid_utf8(@screen2," #{a.to_i}",190,242,0,0,0) 68 refresh 69 if a.to_i == $kotae.to_i 70 sleep 2 71 $tisiki = $tisiki.to_i + $score.to_i 72 @font.put(@screen2,"正解です",50,310,0,0,0) 73 sleep 0.5 74 @font.put(@screen2,"正解は です",50,280,0,0,0) 75 @font2.draw_solid_utf8(@screen2," #{$kotae}",130,274,0,0,0) 76 refresh 77 else 78 sleep 2 79 @font.put(@screen2,"間違いです",50,280,0,0,0) 80 refresh 81 sleep 0.5 82 @font.put(@screen2,"正解は です",50,310,0,0,0) 83 @font2.draw_solid_utf8(@screen2," #{$kotae}",130,300,0,0,0) 84 sleep 2 85 refresh 86 end 87end 88

---追記
何度も繰り返すうちにわかってきたのですが、始める時にスペースを押さないと始まらないようになっているのですが、そのスペースも入力として取得しているようです。そして、なにも入力しないと、期待通りに処理はストップしていました。しかし、数字を押してもやはり、すべて0にされていました。
実行していくと
when SDL::Event2::Quit
exit
この動作をするとちゃんと終了していたので、eventのしょりはきちんとできているとおもうのですが・・・・

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

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

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

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

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

guest

回答2

0

ベストアンサー

SDL::Event2.pollですが、リファレンスによると、取り出すイベントが無い場合はnilを返すそうです。このことから、kotaeawaseメソッドの

Ruby

1while event = SDL::Event2.poll do 2 SDL::Event2.wait

whileループはイベントが無い場合はFALSEとなってしまうので、whileループの中を処理せずに抜けてしまいます(それで回答待ちのキー入力が無い時にもaの評価がされて、後続の処理が動いてしまっていると思います)。
ここは回答が入力されるまで待つ必要があります。やり方としては、startメソッドのようにイベント待ちのwhileループを無限ループで囲う方法もありますが、ネストも深くなりますし、どのみち無限ループで入力待ちにしなければならないので、

Ruby

1while true do 2 event = SDL::Event2.wait #イベントが発生するまで待機する。 3 #イベントが発生したら、そのイベントを返す。 4 case event 5 # 後はflied_onionさんの回答参照 6end

としてみてはどうでしょう。

投稿2016/09/03 04:37

archiver

総合スコア1557

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

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

yusuke.

2016/09/03 05:00

いつもありがとうございます。 大変助かります。ただ、いまできないので明後日ぐらいにしてみます。 できれば今日頑張ってできればいいのですが、部活の時間で作っているので・・・
archiver

2016/09/03 05:18

ちょこちょこ質問を目にしますが、限られた時間の中での作業でどんどん形になってきていますよね。学生で他の勉強もあったりで大変だろうけど、頑張ってq(^ ^q)
flied_onion

2016/09/03 05:31

今、インストールし終わって試してたところですがそうみたいですね。 公式のintroductionでも、その外にloop do ~ exitがあって全体を回してるみたいです。 (キー判定以降は、キーによる影響を受ける行は全部後置ifで処理してたり。) eventとるのになんでwhile使っているのかがちょっと謎なんですけど、公式もrubyマガジンもサンプルではwhile event= SDL::Event2.poll なんですよね。
archiver

2016/09/03 05:45

実は私も今朝rubysdlをインストールしまして、動かしてみたところ回答した挙動が見えたんですよ。ただ、質問者と環境が違うので、リファレンスを見たところ「イベントが無いときはnilを返す」という記述があったので、回答した次第です。 私も検索ベースでruby/sdlの質問に回答してきていたのですが、どれを見てもイベントの取得がwhile event = SDL::Event2::pollなんですよね。なので、今日実際に見るまではここの挙動を誤解してました。しかし、何でこんな書き方なんでしょうね?これだと、nilやFALSE以外が返ってくるように読めますよね。
yusuke.

2016/09/03 11:13

あまりよく理解することができませんが、いろいろ試していただきありがとうございます。 大変助かります。
yusuke.

2016/09/03 13:13

問題なく実行できました。ありがとうございます。 これで、作品も完成しました。たくさんお手伝いいただいたので、この完成した作品をお見せしたいのですが、ちょっと無理だと思うので・・大変ありがとうございました。 おかげで完成しました。
archiver

2016/09/03 13:53

おっ、完成しましたか。おめでとう\(^o^)/ よく作り上げましたね。校内で発表とかするのかな?今回の経験は、きっと、これからにも役に立つと思います。 何はともあれ、完成してよかったです。
yusuke.

2016/09/03 14:03

この作品はコンテストに応募します。 あまりいうといけないのですが去年は部活の先生がすごい詳しい方で、ぼくは全国大会に行きました。そこで、rubyと出会いやり始めたのですが、今年の春先生が転勤してしまい、教えていただける人がいなくなってしまいました。そんなときにこのサイトに出会いどれほどたすけられたことか・・皆さん詳しい方ばかりで大変勉強になりました。いい人たちにも出会えて本当に幸せです。  変に語ってしまいすいません。
guest

0

いくつか気になった事。
まずはruby/sdlを使った事がないので、勘のレベルですが、

https://www.kmc.gr.jp/~ohai/rubysdl_intro.html
と、最初のスペースの判定を見るとSDL::Event2.wait は無くてもいいのかなと思います。
これは次の指摘を直してから試してみてください。

while文の中で気になった事を書きます。

ruby

1 while event = SDL::Event2.poll do 2 SDL::Event2.wait 3 case event 4 when SDL::Event2::Quit 5 exit 6 when SDL::Event2::KeyDown 7 if event.sym == SDL::Key::K1 or event.sym == SDL::Key::KP1 8 a = 1 9 end 10 if event.sym == SDL::Key::K2 or event.sym ==SDL::Key::KP2 11 a = 2 12 end 13 if event.sym == SDL::Key::K3 or event.sym == SDL::Key::KP3 14 a = 3 15 end 16 if event.sym == SDL::Key::K4 or event.sym ==SDL::Key::KP4 17 a = 4 18 end 19 if event.sym == SDL::Key::K5 or event.sym == SDL::Key::KP5 20 a = 5 21 else 22 next 23 puts "0,1,2,3,4,5のどれかを入力してください。" 24 end 25 end 26 end
  • nextの使い方

最後のelseの部分、 nextは呼んだ瞬間次のループに移動してしまいます。
なのでその次の putsは実行されることはありません。
putsをnextの前に実行するようにしましょう。
これはたぶん、0を押しても putsの字が出るからそうしたんじゃないかと思いますが、それは次の指摘で。

  • 複数のif文と最後のelse

キーの判定で複数のif文を連続して書いています。
この場合、各if文は個別に処理されます。
個別に処理されるというのは、自分の前のif文でどうなったかは関係なく、すべてのif文の判定が行われるということです。
だから、このwhen SDL::Event2::KeyDownの中に入ったとき、K1``KP1の判定,K2``KP2の判定,K3``KP3の判定,K4``KP4の判定,K5``KP5の判定(5つつの判定)はすべてチェックされることになります。でも、ここまでは期待している動きだと思います。
問題は最後のelseで、elseとは「それ以外(if文に当てはまる場合以外)」実行されますが、この最後のelseにとってif文とはif event.sym == SDL::Key::K5 or event.sym == SDL::Key::KP5だけとなります。(個別に処理されてるので、K1~K4は別のif文での出来事)
ということは、1~4を押してもこのelseは(5じゃないから)実行されてしまうということになります。
この問題を解決するには、K2~K5の判定は elsif (elseifでは無いことに注意)を使うか、if文ではなくcaseを使う(ちょっとcaseが深くなるのが困りものですけどそこはインデント(処理の深さに応じて行頭を右側にする)をそろえて見やすくします))などがあります。
今回はまず動いてほしいのでK1~K5だった場合はwhileを抜けるようにしてみましょう。

ruby

1 while event = SDL::Event2.poll do 2 SDL::Event2.wait 3 case event 4 when SDL::Event2::Quit 5 exit 6 when SDL::Event2::KeyDown 7 if event.sym == SDL::Key::K1 or event.sym == SDL::Key::KP1 8 a = 1 9 break #(1) 10 end 11 if event.sym == SDL::Key::K2 or event.sym ==SDL::Key::KP2 12 a = 2 13 break #(1) 14 end 15 if event.sym == SDL::Key::K3 or event.sym == SDL::Key::KP3 16 a = 3 17 break #(1) 18 end 19 if event.sym == SDL::Key::K4 or event.sym ==SDL::Key::KP4 20 a = 4 21 break #(1) 22 end 23 if event.sym == SDL::Key::K5 or event.sym == SDL::Key::KP5 24 a = 5 25 break #(1) 26 end 27 puts "0,1,2,3,4,5のどれかを入力してください。" #(2) 28 end 29 end
  • (1) breakは今いるループ(ループが多重になっている場合は一番近いループだけ)を抜ける処理です。

1~5どれかが押されていることがわかったら、このwhile文に用はないので抜けて(脱出して)しまいます。

  • (2) 正しいキーが押された場合、while文から脱出しているので、(2)の位置に来ることはありません。

ここにいるということは、押してほしいキーを押していないという事なので無条件にこの文字は出してよいことになります。

今気が付きましたが、putsでは 0でも良いと書いてあるけど 0の判定がないですね。

とりあえず今気になった事は以上です。

投稿2016/09/03 02:35

flied_onion

総合スコア2604

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

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

yusuke.

2016/09/03 03:48

解答ありがとうございます。 その直していただいたソースをコピペして実行してみましたが、まだ、入力した数字が0のままだったのはなぜでしょうか
flied_onion

2016/09/03 03:54

SDL::Event2.waitは消してみました?
yusuke.

2016/09/03 04:58

応答ありがとうございます。 SDL::Event2.waitは消していませんでした。 また、いま別のパソコンでしているのであさってぐらいになると思いますが、archiverさんの解答も参考にしつつ直してみます。
flied_onion

2016/09/03 05:43

結果的に言えば、それも今の問題とは関係ありませんでした。 別の質問のところにコメントしましたが、インストール方法を早めに書くつもりです。phi(物理演算系?)のインストールは含まないですが、今のクイズの所はなんとか家でも試せるようになると思います。
yusuke.

2016/09/03 13:15

解決しました。詳しく書いていただきありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問