|ごあいさつ |
最近各雑誌やウェブサイトでHSP講座やテクニック集、Q&A集が掲載されております。HSP総本家onion software/おにたま様のページでのHSP掲示板も大盛況です。近日、HSPスプリプとプログラム逆引きテクニックという本も発売されましたし、ここで似たような内容のものを作るのもなんですが、私と同じ初心者の人を対象に、せっかく作った Space War Game で使われているちょっとしたテクニックなんかを披露してみるのもいいかなという気になってつくってみました。はっきりいってアニメーションとかダイレクトなんとかとかを使うテクニックは全然ないし、DLLも作れないので、ほんとに軽い初心者向けの内容ですが、ねたの続く限り不定期で(^^)載せてみて、HSP利用人口の拡大に微力ながらお手伝いしたいと考えておりますm(__)m
また、こんな内容のスクリプトを作って欲しいというお便りもお待ちしております。技術がなくてできないかもしれませんが(ToT)できる限りお手伝いさせていただきたいと考えております。その際は、HSP日曜てくにっく集係までメールをお送りください。
また、as ファイルのサンプルを添付しています。圧縮ファイル形式にしておりますので、ダウンロード&解凍してご使用ください。
|index|
さて、記念すべき第1回目のてくにっくは、意外と見落としがちな点で、HSPのマニュアルにもはっきりとは書かれていない、"dialog"命令のファイルSAVEダイアログでは、ファイル名に拡張子をつけないで保存する、という結果の改善です。
たとえば、
dialog "swg",17,"SWGゲームデータ"
と書けば、開くダイアログが現れて、ファイル名のところに
ファイル名 [*.swg ] ファイルの種類 [SWGゲームデータ(*.swg) ]
と現れます。ここでファイル名を入力することになりますが、ユーザが何気なしに任意のファイル名をつけて、拡張子を入れ忘れると、このファイル名は拡張子なしで保存されてしまいます。
そうすると、今度は改めてファイルを開く際に、たとえば
dialog "swg",16,"SWGゲームデータ"
としてしまうと、ファイルの一覧には拡張子が swg のファイルしか抽出されないので先ほどのファイルは表れません。ここで先ほどのファイルを選択するためには、ファイルの種類のコンボボックスから、全てのファイル(*.*)を選んで先ほどのファイルを選択し、開くボタンを押すという手順になります。これはちょっと面倒で、初心者にはファイルが保存されていないと誤解させてしまいます。
これは、通常のWindowsアプリがこういう場合、拡張子をつけていないファイル名には自動でファイルの種類で選ばれている拡張子をつける設定になっているため、HSP製のプログラムとちょっと扱いが違うから生じる問題でしょう。マイクロソフトも拡張子を表に出させない方針ですし、セーブの際にユーザにわざわざ拡張子をつけさせるのも、なあ、という点で有効なてくにっくをご紹介します。
dialog "swg",17,"SWGゲームデータ" ;ダイアログ出現 if stat=0 : goto *modoru ;キャンセルを押した際元に戻る savefail=refstr ;任意のファイル名を変数savefailに代入 instr a,savefail,".swg" ;ファイル名に拡張子が入っているか見る if a=-1 : savefail=savefail+".swg" ;上で、入っていない場合に拡張子をつける bsave savefail,data ;dataをsavefail名のファイルに保存する
こうした場合、ユーザがわざわざ拡張子をつける場合を除いて、自動で拡張子をつけることができます。ただし、ユーザが拡張子をSWGとか、Swgとかにした場合は、
ファイル名.Swg.swg
とかになってしまいます。まあ、拡張子をわざわざSwgとかswGとかにつけかえる人はいないだろう、という前提ですね。もし気になるようでしたら、上の4〜5行目の判定を繰り返せばいいだけですけれど、普通はいりません(^^;
上の判定式は、律儀にswgの拡張子を残したファイル名をつけるユーザがいることが普通は考えられるから残しています。そういう人にまで
ファイル名.swg.swg
を適用するのはちょっとなあ〜ということで入れています。そういう恐れがない場合は、ファイル名の入った変数に直接拡張子をくっつけても(4行目後半)よいでしょう。
う〜ん、一回目から長くなってしまいましたが、これからも不定期に(^^)がんばっていきたいと思いますので、よろしくお願いいたしますm(__)m
このテーマのサンプルファイルをダウンロードする。
|index|
さて、記念すべき第2回目のてくにっくは、最大数の選択です。まあ、最小数の選択でもいいんですけど、じみなこねたです。地味です。地味ですが、私の今まで作ったプログラムはほとんどこのアルゴリズム(といっていいと思う)だけで動いているといって過言ではありません。その昔(でも今年の4月ごろ)、はじめてHSPでプログラムを組んだとき、複数の数値の中で一番大きい数字を選択するという内容のプログラムが必要でした。ここで、よくあるバブルソートを使ってみようと思ったのですが、……プログラムが長い!たかだか最大数を選択するくらいでいちいち変数を並べ替えていたら、やたらと時間がかかって実用できないのでは?と思いまして、かの初心者、がんばってなんとかしました。それがこれ。
たとえば、配列変数 a に10、21、9、32、4の5個の数字が入っているとします。
a.0=10 a.1=21 a.2=9 a.3=32 a.4=4
このうち、一番大きな数字は a.3 の32ですね。それで、取り出したい変数は a.3の数値であるということが知りたい場合、こうします。
c=0 ;フラグを初期化します。 repeat 50 ;最大数の最大数(上限値) b=50-cnt ;最大数判定用の変数 repeat 5 ;判定される変数の数 d=cnt ;最大変数判定用の変数 if a.d=b : c=1 : break ;最大数の判定 loop if c=1 : break ;最大数がわかったらループから抜ける loop mes "最大数は、変数a."+d+"の数値"+a.d+"です。" stop end
ちょっとコメントがわかりにくいかもしれませんが、要するに、最大数の上限値から順に、対象となる配列変数全てについて、あてはまっているかどうか判定しているだけです。上の例なら、5つの配列変数について、50ですか?49ですか?48ですか?と聞いてまわっていることになります。はまっている32までくれば、フラグ c に1を代入し、ループを抜けます。これだけです。簡単でしょ? Space War Game も判定に関してはこのアルゴリズムだけでできてます。このアルゴリズムの欠点は、最大数の最大数(上限値)という数字が、10000とか100000とかになると、時間がかかりすぎてしまうという点です。Space War Game で銀英伝風の10000隻とかの艦隊数にしずらいのは、実はこれのせいだったりします。全てのこの手のルーチンをいじらないといけないので、とてもじゃないですが作り直したほうがましなんです(T-T)
それから、もし変数のうちの最小値を見つけたい場合は、上の3行目の b=50-cnt という部分を、b=cnt とするだけでよいです。
いやあこの判定って、単純ですけど、単純な論理で動いているパソコンには丁度いいかもしれません。昔のパソコンでしたら遅くて使えないんでしょうけど、今のヘルツだけはやたら早いパソコンだったら、十分に対応できるでしょう。後はもっと使いやすいユーザーインターフェースですね。ということで、次回は……
このテーマのサンプルファイルをダウンロードする。
|index|
さて、記念すべき第3回目のてくにっくは、自動で消えるダイアログです。徒然日誌にも書いてましたが、意外と簡単に作れてしまいました。ただ、結構長いので、ここに載せるのは今のうちくらいで、将来的には別ページにする予定です。なお、今週からサンプルファイルをダウンロードできるようにしましたので、いちいちコピーして加工して試さなくても、そのままご使用していただくことができます。
では、長いのでさっそくご覧いただきませう。。。
ファイル"あなたのお好きなファイル.as" #include "cdia.as" cdia "自動で消える\nダイアログ","タイトルバーの文字",120 end ファイル"cdia.as" #module ;モジュールの宣言 #deffunc cdia str,str,int ;モジュール変数4つの宣言 mref mojiretunaiyou,32 ;モジュール変数の命名。以下同じ mref mojiretutitle,33 mref waittime,2 if waittime=0 : waittime=150 ;自動で消える時間が設定されていない場合150に設定 notesel mojiretunaiyou ;行数を判定するためにnoteselを使用 notemax y ;全部の行数判定 mojiretunaiyou=mojiretunaiyou+"\r";最後の文字に終了コードをつけます。 x=0 repeat y instr m.cnt,mojiretunaiyou,"\n",x ;最初の文字や、前の改行コードから何文字 ;目に改行コードがあるか判定して、配列変 ;数 m に代入 if m.cnt=-1 : instr m.cnt,mojiretunaiyou,"\r",x : break ;改行コードがなかった場合、終了コードが何文字目かを判定してます。 x=x+1+m.cnt ;前の改行コードの位置をインデックスとして指定しています。 loop c=0 repeat 200 ;おなじみの最大数判定処理の開始です。 b=200-cnt repeat y if m.cnt=b : c=1 : break ;1行の文字数がもっとも多い行を判定 loop if c=1 : break loop screen 10,b*6+15,y*14+30,8,250,300 ;表示用のスクリーンを設定(10番です) font "MS Pゴシック",13 ;このサイズが、一番ダイアログっぽい gsel 10,2 ;最前面に表示 redraw 0 ;お約束の、非表示 color 181,166,165 : boxf 0,0,b*6+14,y*14+29 : color 0,0,0 ; それらしい色に塗りつぶしています。 title mojiretutitle ;ダイアログタイトルを表示 pos 7,0 ;表示位置指定 mes " " ;見やすくするために、最初に一行あけてます。 mes mojiretunaiyou ;ここで文字列を表示 mes " " ;見やすくするために、最後に一行あけてます。 redraw 1 ;お約束の再表示 repeat waittime ;消えるまでの時間指定 stick a,1 ;キー判定 if a=512 { ;右クリックした場合 a=0 repeat -1 stick a,1 if a=256 : break ;左クリックするまで無限ループ wait 2 ;ここを1とかawaitに変えると、反応が良くなります loop } if a=256 : break ;左クリックするまで、指定時間ループ wait 2 ;ここを1とかawaitに変えると、反応が良くなります loop gsel 10,-1 : gsel 0,1 ;ダイアログを消去し、元の画面(0番)を前面に表示 return ;モジュール終わり #global
どうですか、ご理解いただけました?(^^;A 要するに、文字列に応じてダイアログのサイズを決定し、マウスの左右のキー判定を行って消去したり停止させたりしています。まあ、何もなければサンプルをそのまま使用していただいて結構です。ちょっと仕様を変更したいというときに、上のコメントを参考にしてください。
HSPのマニュアル風に仕様を書いてみると、
cdia "message","option",p1 [自動消去確認ダイアログ] p1=1〜(150) : 消去までの時間
説明 自動で消えるダイアログです。"message"で指定した内容を表示するダイアログスが現 われます。また、"option"でダイアログのタイトルバー文字列を指定することができま す。(省略した場合はタイトルに何も表示されません)。 ダイアログは、マウスの左クリックで閉じられ、ウィンドウ0に戻ります。右クリック すると、次に左クリックされるまで、ダイアログは閉じられません。 p1でダイアログが消去するまでの時間が指定できます。p1に-1を指定すると、マウスの 左クリックを押すまでダイアログは自動で消去しなくなります。
こんな感じでしょうか(^^;なお、設定上1行の文字数は半角200文字、全角100文字まで対応できます(設定変更すれば変わります)。また、ウィンドウはダイアログに10番、もとのウィンドウに0番を使用しています(これも、設定変更すれば変わります。)名前も、cdia(auto Close DIAlog)から変えていただいても結構ですし、自由に加工、変更して使用していただいても、そのまま使用していただいても結構です。わからない点がございましたら、こちらまでご連絡ください。
このテーマのサンプルファイルをダウンロードする。
|index|
さて、記念すべき第4回目のてくにっくは、画面をポイントしただけでその部分の情報を表示する仕組みで、HSPのマニュアルに出ていたものの応用です。使ってみると結構かれーですが、中身は泥臭い、白鳥の水面下の水かきみたいなプログラムです。Space War Game では、星系をポイントするだけで、その星系の情報を表示する部分に用いていました。
font "MS ゴシック",40 ;フォントの設定 *main x=mousex : y=mousey ; マウスポイントの座標取得 pos 200,150: mes "○" ; 惑星?表示 title "X="+x+" Y="+y ; マウスポインタの座標参照用 gosub *mesdel ; メッセージ消去 gosub *atari ; メッセージ表示 wait 2 ; いつものように、1とかawaitにすると反応向上 goto *main *mesdel color 255,255,255 ; 白色 boxf 0,0,145,40 ; 塗りつぶし color 0,0,0 ; 黒色 return *atari if (x>=200) & (x<=235) & (y>=150) & (y<=185) : pos 0,0 : mes "あたり!" ;この4点セットでマウスの座標判定をしている。 return
ということで、メイン部分は非常にシンプルですが、*atariにあたるところは星の数だけ座標を調べて、if文をひたすら並べることになります。この部分を応用するとクリッカブルマップみたいに、ポイントしたところをクリックして選択することができます。おっと、あんまりネタがないのでこれは次回のネタにします(^^;A
このテーマのサンプルファイルをダウンロードする。
|index|
さて、記念すべき第5回目のてくにっくは、画面の特定の部分をクリックすることでその部分のクリックに応じたイベントを生じさせるという、クリッカブルマップについてです。アドベンチャーゲームなんかで使えるかもしれません。このてくにっくは、前回のてくにっくとほとんど同じだったりします。
font "MS ゴシック",40 ; フォントの設定 ss=0 : a=0 ; 変数の初期化 *main repeat ; 無限ループ x=mousex : y=mousey ; マウスポイントの座標取得 pos 200,150: mes "○" ; 惑星?表示 title "X="+x+" Y="+y ; マウスポインタの座標参照用 gosub *mesdel ; メッセージ消去 gosub *atari ; メッセージ表示 ;ここから下が、今回のてくにっく getkey a,1 ; クリック判定用 if a=1 : x=mousex : y=mousey : break ; クリック時点でのマウス座標取得 wait 2 ; いつものように、1とかawaitにすると反応向上 loop if (x>=200) & (x<=235) & (y>=150) & (y<=185) : ss=1 ; この4点セットでマウスの座標判定をし、変数を取得している。 if ss=0 : goto *main ; 関係ないクリックの場合、ループに戻る dialog "惑星番号 "+ss+" をクリックしましたね。";イベント(^^; ss=0 : a=0 ; 変数初期化 goto *main *mesdel color 255,255,255 ; 白色 boxf 0,0,145,40 ; 塗りつぶし color 0,0,0 ; 黒色 return *atari if (x>>=200) & (x<=235) & (y>=150) & (y<=185) : pos 0,0 : mes "あたり!" ;この4点セットでマウスの座標判定をしている。 return
今回は惑星部分をクリックするとダイアログが出てきます。
ということで、前回とほとんど同じような内容だったりします。これだけで、画面内の特定の絵の座標を指定しておいて、クリックさせることでアイテムを取得させるといった使い方もできます。簡単でしょ〜(^o^)
このテーマのサンプルファイルをダウンロードする。
|index|
ひっじょーに久しぶりの記念すべき第5回目のてくにっくは、第2回目のてくにっくについてのくま様からのもっと"効率的"なてくにっくについてでございます。第2回目の一番大きな(小さな)数字を選択するというてくにっくは、私がもっとも多用したアルゴリズムなのですが、これがもっと効率的になるよ!というお便りをくま様からいただきました。
すなわち、まず第2回目のアルゴリズムでは、最大値から順に、この数字ですか?と全てのデータに対して何度も繰り返して聞くという手法です。全てのデータに、あなたは150ですか?と聞いてまわり、どれもそうでなかったら、あなたは149ですか?と、また全てのデータに聞いてまわります。最悪、最低値付近まで何度も何度も繰り返して聞かれるので、これが人間世界なら、「いい加減にしろ!」といわれそうですね(^^;;;けれどコンピュータは黙々と聞いてまわり、聞かれていきます。
これに対してくま様からいただいたアルゴリズムでは、1回しか聞いて回ることはしません。つまり、一個メモ帳(変数)を用意して、そこに今の最大値と名前(データ番号)を記入します。順番にデータに数字を聞いて回る際、聞いた数字がメモ帳(変数)の数字より大きければ、メモ帳を書き直します。全員に聞いて回り終えれば、最後にメモ帳に記入した数字と名前(データ番号)が、全体の最大値と、その持ち主のデータということになります。具体的には、たとえば、配列変数 a に10、21、9、32、4の5個の数字が入っているとします。
a.0=10 a.1=21 a.2=9 a.3=32 a.4=4
このうち、一番大きな数字は a.3 の32ですね。それで、取り出したい変数は a.3の数値であるということが知りたい場合、
c=-1000 ;最大値の変数を初期化します。 d=-1 ;最大値の変数番号を初期化します。 repeat 5 ;全データの個数です if a.cnt>c : c=a.cnt : d=cnt ;最大数の判定 loop mes "最大数は、変数a."+d+"の数値"+a.d+"です。" stop end
なんと、これだけで判定できてしまいます。そのうえもっと早くなります。20回平均でだいたい4〜5倍早い結果になるうえ、1回しかループを回さないので結果の出力時間も安定します。第2回目のアルゴリズムでは、結果の出力が、最大値が上限値付近にある場合に速くなり、下限値付近にある場合に遅くなり、ループを回す回数がデータによって異なるため安定しません。さらに、一番早い場合でも、上のアルゴリズムより時間がかかります。唯一第2回目の方が早いのは、最大値が上限値と同じ場合だけです(^^;これはどう考えてもこちらの方が早いですね。
もちろん、「最大数の判定」のところで不等号を逆にしてやれば、最小数の判定もできます(この場合は、変数を巨大な数で初期化する必要があります)。
よくよく眺めてみると、第2回目のアルゴリズムでも最大数を判定していますが、この時イコールを使っているのが時間と手間のかかる原因ですね(^^;A不等号を使えば簡単でしたが、さすが初心者、そこまで思い至らず、でした。
ということで、新たなてくにっくを得ることができ、今後はもっと速いプログラムを組むことができるようになりました。くま様ありがとうございましたm(__)m皆様も私のてくにっくのこんなところが変だ、とかこんなところはこうした方がいいんちゃうん?というお便りもどしどしお送りくださいませ。。。門外不出の秘伝の法として極秘扱いでない限り、こちらでもご紹介させていただくこともあります。
最近(2002/9/22)すっかりDelphiプログラマーの私ですが、ここでのてくにっくはアルゴリズムなどどの言語でも同じ発想で使えるものもあります。将来的には「Delphiてくにっく集」になるかもしれませんが、皆様今後とも「HSP日曜てくにっく集」をよろしくお願いいたします。。。
このテーマのサンプルファイルをダウンロードする。
|index|