HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2021
0915
孝乃花インプットに文字が打ち込めません8解決


孝乃花

リンク

2021/9/15(Wed) 22:54:19|NO.93881

英単語ゲームを作っているのですが、インプットに文字を打ち込むことができません。
解決策を教えていただけると助かります。
よろしくお願いします。
以下スクリプトです。
*Start
screen 0,600,400
title "修造ENGLISH"
redraw 0
color:boxf
color 255,0,0:font "HG明朝E",50:pos (870-50*11)/2,100:mes "修造ENGLISH"
color $FF,$FF,$00:font "HG明朝E",30:pos (500-30* 6)/2,180:mes "~LEVEL1~"
color 255,255,255:font "HG明朝E",16:pos (600- 8*15)/2,250:mes "[Enter]キーで開始"
color $FF,$FF,$FF:font "HG明朝E",16:pos (600- 8*15)/2,282:mes "[ESC]キーで終了"
redraw 1
repeat
stick key
if(key&32):break
if(key&128):end
await 20
loop

notesel buf
ab=0
ac=1

time=10

*main
cls
mes "正解="+seikai+"":mes "不正解="+huseikai+""
noteload "type1.txt",50000
noteget a,ab
mes a;1行目表示
noteget b,ac
sdim kaitou,500
objmode 2
font msgothic,24
objsize 200,40
input kaitou
mes "PUSH ENTER"
if time<1:goto *gameover ;残り時間が0以下ならkeyを0にする
time=time-1;残り時間を減らす
pos 300,300 ;描画する場所を設定
mes "残り時間:"+time
wait 100
stick ky
if ky=32:gosub*judge//もしEnterが押されたらloopを抜けて次の行へ
wait 1
goto *main

*judge
if kaitou=b{
mes "正解"
seikai=seikai+1
}else{
mes "不正解"
huseikai=huseikai+1
}
wait 100
ab=ab+2
ac=ac+2
if huseikai=3:pos 120,200:color 0,0,0:mes"Game Over":redraw 1:await 1000:goto *Start//ゲームオーバー処理
return

*gameover
mes "時間切れ"



この記事に返信する


ねんねこ

リンク

2021/9/16(Thu) 09:19:39|NO.93882

こうすればすこしは改善するのかな?

*Start screen 0,600,400 title "修造ENGLISH" redraw 0 color:boxf color 255,0,0:font "HG明朝E",50:pos (870-50*11)/2,100:mes "修造ENGLISH" color $FF,$FF,$00:font "HG明朝E",30:pos (500-30* 6)/2,180:mes "~LEVEL1~" color 255,255,255:font "HG明朝E",16:pos (600- 8*15)/2,250:mes "[Enter]キーで開始" color $FF,$FF,$FF:font "HG明朝E",16:pos (600- 8*15)/2,282:mes "[ESC]キーで終了" redraw 1 repeat stick key if(key&32):break if(key&128):end await 20 loop notesel buf ab=0 ac=1 time=10 kaitou="" *main cls mes "正解="+seikai+"":mes "不正解="+huseikai+"" noteload "type1.txt",50000 noteget a,ab mes a;1行目表示 noteget b,ac objmode 2 font msgothic,24 objsize 200,40 input kaitou mes "PUSH ENTER" if time<1:goto *gameover ;残り時間が0以下ならkeyを0にする time=time-1;残り時間を減らす pos 300,300 ;描画する場所を設定 mes "残り時間:"+time wait 100 stick ky if ky=32:gosub*judge//もしEnterが押されたらloopを抜けて次の行へ await 1000 goto *main *judge if kaitou=b{ mes "正解" seikai=seikai+1 }else{ mes "不正解" huseikai=huseikai+1 } wait 100 ab=ab+2 ac=ac+2 if huseikai=3:pos 120,200:color 0,0,0:mes"Game Over":redraw 1:await 1000:goto *Start//ゲームオーバー処理 return *gameover mes "時間切れ"



とあるプログラマ

リンク

2021/9/16(Thu) 13:40:19|NO.93887

cls命令は画面内のオブジェクトもすべて消去します。
input命令などは実行されるたびにオブジェクトを新たに設置します。

つまり*mainに行くたびに、画面内のinputが消されては作られて消されては作られて…の繰り返しになっています。
なので1秒ごとに何も入力されていない新しいinputが配置されているので、見かけ上文字が消えているようになっています。

inputやmesbox、buttonのようなオブジェクト配置命令は、基本1回のみの呼び出しで使用します。


mesなどの文字を変更する場合は、boxf等で画面を塗りつぶしてから新しい文字をmesします。(boxfではオブジェクトは消去されません)

inputやmesboxなどの文字を変更する場合は、objprmという命令を使います。


また、noteloadによるテキストファイル読み込みも毎回行うのではなく、最初の一度のみ読み込み、変数に内容を保存しておくのが適切です。


今回の場合はmesの文字を変更するため、boxfにより塗りつぶしたあと再度mesする方法が一般的です。
したがって以下のように修正します。


*Start screen 0,600,400 title "修造ENGLISH" redraw 0 color:boxf color 255,0,0:font "HG明朝E",50:pos (870-50*11)/2,100:mes "修造ENGLISH" color $FF,$FF,$00:font "HG明朝E",30:pos (500-30* 6)/2,180:mes "~LEVEL1~" color 255,255,255:font "HG明朝E",16:pos (600- 8*15)/2,250:mes "[Enter]キーで開始" color $FF,$FF,$FF:font "HG明朝E",16:pos (600- 8*15)/2,282:mes "[ESC]キーで終了" redraw 1 repeat stick key if(key&32):break if(key&128):end await 20 loop ab=0 ac=1 time=10 // オブジェクト配置命令は基本的には最初の一度のみ実行します。 cls objmode 2 font msgothic,24 objsize 200,40 sdim kaitou,500 input kaitou notesel buf noteload "type1.txt",50000 // メインループ内ではclsやinput、noteloadは行いません。 *main redraw 0 color 255, 255, 255 boxf color 0, 0, 0 pos 0, 100 mes "正解="+seikai+"":mes "不正解="+huseikai+"" noteget a,ab mes a;1行目表示 noteget b,ac mes "PUSH ENTER" if time<1:goto *gameover ;残り時間が0以下ならkeyを0にする time=time-1;残り時間を減らす pos 300,300 ;描画する場所を設定 mes "残り時間:"+time redraw 1 wait 100 stick ky if ky=32:gosub*judge//もしEnterが押されたらloopを抜けて次の行へ wait 1 goto *main *judge if kaitou=b{ mes "正解" seikai=seikai+1 }else{ mes "不正解" huseikai=huseikai+1 } wait 100 ab=ab+2 ac=ac+2 if huseikai=3:pos 120,200:color 0,0,0:mes"Game Over":redraw 1:await 1000:goto *Start//ゲームオーバー処理 return *gameover mes "時間切れ"



孝乃花

リンク

2021/9/17(Fri) 06:21:29|NO.93895

ねんねこさん、とあるプログラマさん、答えていていただきありがとうございます。
一歩前進できました。
とあるプログラマさんの方で、スクリプトを修正したところ、文字が打ち込めるようになりました。
ただ、①判定が遅い、②問題ごとで書いた文字が消えない
という2点の悩みがあります。

stick key=32
if ky=32

はrepeat loopで使うべきという記事を見つけたのですが、それが関係しているのでしょうか?
回答していただけると助かります。よろしくお願いします。



とあるプログラマ

リンク

2021/9/17(Fri) 17:39:55|NO.93899

>>①判定が遅い

stickやgetkeyはそれらが実行された「瞬間」のキー状態を格納します。

このプログラムは1秒間 wait 100 で停止しますので、stickでキー状態を認識できるのは wait 100 と goto *main してループした次回の wait 100 の間にある stick が実行される一瞬です。

いかなる状態でもキー入力を即座に受け付けるには、onkey 命令を使用します。
この命令はキー入力が起こった瞬間に、指定したラベルへジャンプします。

その際 iparam に入力されたキーのキーコードが代入されています。
Enterは13なので、iparamが13だったときだけ必要な処理を行います。


>>②問題ごとで書いた文字が消えない

inputの中身を消すには objprm を使います。
その際必要なオブジェクトIDは、inputやmesbox、buttonなどのオブジェクト配置命令を実行した際に stat に代入されるので、それを変数に保存しておきます。


*Start screen 0,600,400 title "修造ENGLISH" redraw 0 color:boxf color 255,0,0:font "HG明朝E",50:pos (870-50*11)/2,100:mes "修造ENGLISH" color $FF,$FF,$00:font "HG明朝E",30:pos (500-30* 6)/2,180:mes "~LEVEL1~" color 255,255,255:font "HG明朝E",16:pos (600- 8*15)/2,250:mes "[Enter]キーで開始" color $FF,$FF,$FF:font "HG明朝E",16:pos (600- 8*15)/2,282:mes "[ESC]キーで終了" redraw 1 repeat stick key if(key&32):break if(key&128):end await 20 loop ab=0 ac=1 time=10 // オブジェクト配置命令は基本的には最初の一度のみ実行します。 cls objmode 2 font msgothic,24 objsize 200,40 sdim kaitou,500 input kaitou ID_input = stat // オブジェクト設置系の命令後には stat にオブジェクトIDが代入されています notesel buf noteload "type1.txt",50000 // onkeyを使って、キーが押されたら*judgeに飛びます onkey gosub *judge // メインループ内ではmesの再描画のみ行います。 *main redraw 0 color 255, 255, 255 boxf color 0, 0, 0 pos 0, 100 mes "正解="+seikai+"":mes "不正解="+huseikai+"" noteget a,ab mes a;1行目表示 noteget b,ac mes "PUSH ENTER" if time<1:goto *gameover ;残り時間が0以下ならkeyを0にする time=time-1;残り時間を減らす pos 300,300 ;描画する場所を設定 mes "残り時間:"+time redraw 1 wait 100 // 不要削除部分 /* stick ky if ky=32:gosub*judge//もしEnterが押されたらloopを抜けて次の行へ wait 1 */ goto *main *judge // *judgeでの処理を実行する間、再度Enterを押されることを防ぐため、 // *judge中は onkey 0 で onkey の割り込みを一時停止します。 onkey 0 // onkeyから飛んできた場合は iparam に文字コードが代入されています。 // 文字コードはgetkeyのものと同じです。 // ここでは Enter(13) の場合は必要な処理を行います。 if iparam=13 { if kaitou=b{ mes "正解" seikai=seikai+1 }else{ mes "不正解" huseikai=huseikai+1 } wait 100 ab=ab+2 ac=ac+2 if huseikai=3:pos 120,200:color 0,0,0:mes"Game Over":redraw 1:await 1000:goto *Start//ゲームオーバー処理 // input の中身を空 "" に設定します。 objprm ID_input, "" } // 止めてあった onkey を再度動かします。 onkey 1 return *gameover mes "時間切れ"



孝乃花

リンク

2021/9/17(Fri) 22:44:04|NO.93902

とあるプログラマさん、わかりやすい解説と修正スクリプトありがとうございます。
問題が解消しました。
とても参考になりました。何時間かけてもできなかったので、感動です。
あと3つだけ教えていただきたいです。
①タイピングを速くすれば速くするほど、残り時間が一気に減ってしまいます。
どうしたらよいでしょうか?
②ゲーム終了と同時にインプットキーへの入力をストップするにはどうしたらよいでしょうか?
③ab=0,ac=1,noteget a,ab noteget b,acってどういう意味なのでしょうか?
どうかご回答よろしくお願いします。



メルクーフ

リンク

2021/9/18(Sat) 08:31:15|NO.93903

 他の方が回答されていたので不要かと思いましたが、まだ問題があるようなので、最初のスクリプトを基に私のやり方で変更した物を挙げておきます。

 その前に質問についての回答もしておきます。

>> ①タイピングを速くすれば速くするほど、残り時間が一気に減ってしまいます。どうしたらよいでしょうか?
 onkeyを使うと、キーを押すたびにwaitの残り時間が棄却されます。私は通常、onkeyを使わず、随所にstickで判定するようなスクリプトを記述するようにしています。

>> ②ゲーム終了と同時にインプットキーへの入力をストップするにはどうしたらよいでしょうか?
 とりあえずclrobjを入れておきました。inputのボックスを消すことで実現させています。

>> ③ab=0,ac=1,noteget a,ab noteget b,acってどういう意味なのでしょうか?
 noteget a,abは『文字列変数aにnoteloadで読みこんだテキストのab(+1)行目を代入する』という意味です。abが0なので、aには0+1で1行目の文が入ります。
 type1.txtには奇数行目に問題、偶数目に解答が入っているので、abとacを2ずつ足すことで毎回aには問題が、bには解答の文字列が代入されることになります。


*Start screen 0,600,400 title "修造ENGLISH" redraw 0 color:boxf color 255,0,0:font "HG明朝E",50:pos (870-50*11)/2,100:mes "修造ENGLISH" color $FF,$FF,$00:font "HG明朝E",30:pos (500-30* 6)/2,180:mes "~LEVEL1~" color 255,255,255:font "HG明朝E",16:pos (600- 8*15)/2,250:mes "[Enter]キーで開始" /*color $FF,$FF,$FF:font "HG明朝E",16*/:pos (600- 8*15)/2,282:mes "[ESC]キーで終了" : ; 上と重複しているので不要。 redraw 1 repeat stick key if(key&32):break if(key&128):end await 20 loop notesel buf ab=0 ac=1 time=500 : ; await 20を500回くり返すことで約10秒に変更。 noteload "type1.txt",50000 : ; 外に出す。 sdim kaitou,500 : ; 外に出す。初期化は代入で行う。 *main cls : ; このスクリプトならclsでいいと思う。 mes "正解="+seikai+"":mes "不正解="+huseikai+"" noteget a,ab mes a noteget b,ac kaitou="" : ; 初期化。 objmode 2 : ; clsを残したので、これらも残す。 font msgothic,24 objsize 200,40 input kaitou objsel 0 : ; これが無いと2回目以降にinputボックス内に入力カーソルがデフォで出ない。 mes "PUSH ENTER" ; mainを2つに分ける。 *main_2 time=time-1 redraw 0 : ; 画面のチラツキを防ぐ。 color 255,255,255 : boxf 300,300,599,399 : ; 残り時間の表示を消去。 color 0,0,0 : ; 消去の際に色を変えたので、文字の色に黒を指定。 pos 300,300 mes "残り時間:"+str((time+49)/50) : ; timeが49以下になると0と表示されるのを防ぐために49を足す。 redraw 1 if time<1:goto *gameover : ; 残り時間を表示させてから*gameoverに飛ぶように順番変更。 ; wait 100は使わない。 stick ky if (ky&32)!=0 :goto *judge : ; ifは私の好みの書き方なだけの変更。gosubをgotoに変更。 await 20 : ; wait 1を変更。 goto *main_2 : ; 変更。 *judge if kaitou=b{ mes "正解" seikai=seikai+1 }else{ mes "不正解" huseikai=huseikai+1 } wait 100 ab=ab+2 ac=ac+2 if huseikai=3:pos 120,200:color 0,0,0:mes"Game Over": /* redraw 1は不要。*/ : goto *modoru : ; 別ラベルに飛ぶように変更。 goto *main : ; gosubをgotoに変えたのでreturnも変更 *gameover mes "時間切れ" *modoru clrobj:await 2000:goto *Start : ; clrobjでinputボックスを消去し、1秒では短いと思ったので2秒に変更。その後で*Startに戻る。



とあるプログラマ

リンク

2021/9/18(Sat) 11:57:23|NO.93905

メルクーフさんがほとんど解説してくださったので私からの解説はあまりありませんが、一応私の oncmd を使った方法での修正案も載せておきますね。


>>①
メルクーフさんが仰る通り、HSPの仕様上wait/await中に割り込みが発生すると、割り込みから帰ってきたあとの残り時間に関わらず wait/await が終了して次の行に移動してしまいます。

私の場合はこの問題を修正して、割り込みが発生しても残り時間もちゃんと待機してくれる修正版 waitEX を作りました。
冒頭の#module~#global部分でそれが定義されています。

この程度のプログラムではさほど問題はないと思いますが、常に小間隔でrepeat~loopしているとCPU使用率が高くなってしまいますし、await の待機中はやはり入力を受け付けてくれないので、私はこの onkey と waitEX を使った方法を使いました。

どちらの方法が良いかは、まあぶっちゃけ好みですね。
自分がやりやすい方、分かりやすい方を選べばいいと思います。


>>②
こちらもメルクーフさんが仰る通り、clrobjを使う方法もありますし、objenableという命令を使う方法もあります。
違いは消すか無効化するかです。
これも好みでしょう。

ただしclrobjで消した場合は、また使いたいときは再度 input で配置する必要があります。
objenableで無効化した場合は、再度objenableで有効化するだけです。中身を消すにはobjprmも必要になりますが。


>>③
完璧にメルクーフさんが解説してくださったので私から言うことはないですが、一つだけ何故 +1行目なのかだけ補足すると、コンピュータ的には順番は0から始まるからです。

我々人間からすると一番上の行から 1行目・2行目・3行目… ですが、コンピュータ的には 0行目・1行目・2行目… といった感じです。


// モジュールはじめ #module #uselib "WINMM.DLL" #func timeGetTime "timeGetTime" #func timeBeginPeriod "timeBeginPeriod" sptr #func timeEndPeriod "timeEndPeriod" sptr // 要約すると、waitEX が呼び出されてから指定待機時間後のティック(≒時刻)まで待機します。 #deffunc waitEX int time, \ local ExitTick timeBeginPeriod 1 ExitTick = timeGetTime() + time * 10 while (timeGetTime() < ExitTick) wait@hsp max(0, (ExitTick - timeGetTime()) / 10) wend wait@hsp 0 timeEndPeriod 1 return #global // モジュール終わり *Start screen 0,600,400 title "修造ENGLISH" redraw 0 color:boxf color 255,0,0:font "HG明朝E",50:pos (870-50*11)/2,100:mes "修造ENGLISH" color $FF,$FF,$00:font "HG明朝E",30:pos (500-30* 6)/2,180:mes "~LEVEL1~" color 255,255,255:font "HG明朝E",16:pos (600- 8*15)/2,250:mes "[Enter]キーで開始" color $FF,$FF,$FF:font "HG明朝E",16:pos (600- 8*15)/2,282:mes "[ESC]キーで終了" redraw 1 repeat stick key if(key&32):break if(key&128):end await 20 loop ab=0 ac=1 time=10 cls objmode 2 font msgothic,24 objsize 200,40 sdim kaitou,500 input kaitou ID_input = stat notesel buf noteload "type1.txt",50000 onkey gosub *judge *main redraw 0 color 255, 255, 255 boxf color 0, 0, 0 pos 0, 100 mes "正解="+seikai+"":mes "不正解="+huseikai+"" noteget a,ab mes a;1行目表示 noteget b,ac mes "PUSH ENTER" if time<1:goto *gameover ;残り時間が0以下ならkeyを0にする time=time-1;残り時間を減らす pos 300,300 ;描画する場所を設定 mes "残り時間:"+time redraw 1 // 残り時間を考慮する waitEX を使用します。 waitEX 100 goto *main *judge onkey 0 if iparam=13 { if kaitou=b{ mes "正解" seikai=seikai+1 }else{ mes "不正解" huseikai=huseikai+1 } wait 100 ab=ab+2 ac=ac+2 if huseikai=3:pos 120,200:color 0,0,0:mes"Game Over":redraw 1:await 1000:oncmd 0:goto *Start//ゲームオーバー処理 objprm ID_input, "" } onkey 1 return *gameover oncmd 0 mes "時間切れ" // オブジェクトを無効化 objenable ID_input, 0



孝乃花

リンク

2021/9/19(Sun) 08:29:53|NO.93911

メルクーフさん、とあるプログラマさん、丁寧な解説と修正プログラムの提案ありがとうございます。
自分が再現したいと思っていた形になりました!
いろいろなアプローチの仕方があることがよくわかりました。
これから、画像を入れたり、ゲーム性を高めたり、ランキング機能をつけたりしていくことを目指していきます。
また壁にぶつかった際、お助けいただけると嬉しいです。よろしくお願いいたします。
ご協力ありがとうございました。



ONION software Copyright 1997-2025(c) All rights reserved.