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