モジュール
「モジュールって一体なんだろう」って説明から…。
プログラムを再利用可能な形にまとめたサブルーチン集であり、メインスクリプトとは別空間になります。
gosubって言うものが以前出てきましたよね?
簡単に言うとアレです。
あのgosubでの場合、サブルーチン内部で使用する変数は当然決まっています。
例えば変数Aをルーチン中で加工しているが、別の時にそのサブルーチンを使いたいとなったとします。
しかし、内部で使用している変数Aは別の所で既に使っているので加工したくありません。
じゃあ2回目の時は、2回目かの判断をして2回目であるならば変数Bを使えばいい、となりそうです。
しかし、3回4回と使うかもしれません。
その時にまた別の変数を用意してソレを使うようにしますか?
後で見たとき、非常に分かりにくいサブルーチンとなっていることでしょうし、
何よりわざわざ無理に同じ所を通過させる必要があるのでしょうか?
同じロジックのものを2つ3つと必要な分だけ作れば2回目であるからこの変数を使うってことがなくなる。
しかし、同じ形のものを2つ3つも用意しておくのはムダってもんです。
…それじゃあどうすればいいんだって時に使うのがモジュールなわけです。
冒頭に書いたようにモジュールはメインプログラムとは別空間となっており、
メインプログラムで使用している変数との衝突がありません。
つまり、先ほどのサブルーチン内で変数Aを使っているが別の所でも変数Aを使っているのでおかしくなる
って事が回避できるわけです。
また、流れとしては同じ様に使いたいけど全く同じだと困るって場合に役立ちます。
例えば、外枠だけのboxfのように塗りつぶさないボックスをクリック位置に描きたい、とします。
サブルーチンでもモジュールでも外枠だけの四角を描くロジックは一緒のlineで描くとします。
四角を描くのは同じだけど全く同じではなく、クリックされた位置に描くという条件があるわけですね。
つまり、クリックされた位置情報を四角を描くロジックに渡してやらなければなりません。
サブルーチンだと、処理に入る前にロジック内でクリック位置情報を使う変数に渡さねばなりません。
サブルーチンに入る直前で変数に入れてコメントを念入りに書いておけば
後で見たときでも「あぁここでサブルーチンに渡している変数なんだな」とわかるでしょう。
でもサブルーチンに渡す用の変数を1つ余分に用意しなければなりませんし、
先ほど書いた様に、別の所でも変数を使いまわしていたり、
別の箇所でサブルーチン用に入れていたりしたらゴチャゴチャして分かりにくくなってしまいます。
モジュールの場合、サブルーチンにジャンプするというより命令を呼び出すといったほうがシックリ来ます。
モジュールへは他の命令と同じ様な扱いで、当然モジュールに渡す為に別の変数に入れるのはOKだし、
通常のパラメータとして渡す方法だと余分に変数を用意する必要もない。
なんだかんだでモジュールにしたほうがイイ(場合が多い)ってことです。
では次にモジュールとはどのように書けばいいのか説明していきます。
モジュールの開始はプログラム内に「#module "モジュール名"」という一文を書きます。
上記を書くことで、ココから下のプログラムはモジュールだという目印となるわけです。
HSP2.55ではパラメータであるモジュール名に「""」としてもエラーにはなりませんでしたが
HSP2.6ではエラーとなってしまうので、適当に名前を決めるか完全に省略しましょう。
モジュール名の規則では「半角英数、アンダーバーのいずれかで18字以内」となっていますが、
書いてみたところ、19文字以上やひらがな等を使用しても普通に動いています。
それでも、一応ヘルプに従いましょう。
さて、モジュールの開始点は決まりましたが終了点が決まっていません。
これでは、モジュール以降に書いたメインプログラムはどこからかがわかりません。
ココまでがモジュールだ、という開始点と対を成す終了点を書かなければならないわけですが、
その一文は「#global」です。パラメータはありません。
コレで1モジュールができました。出来たといっても開始と終了だけですけど。
既に書いたように、モジュールはメインプログラムとは別空間です。
コレは例え、下記の様に書いてもメインプログラムからモジュール内には入りません。
#module "module_test"
end ; 通常上から順次実行すると,ココで終了するが…
#global
stop
じゃあ、一体どのようにすれば入られるようになるのかと言うと、
モジュールの説明で、サブルーチンへのジャンプではなく命令を呼び出す感じと書きましたよね?
#deffunc命令でヘルプにもあるように新しく命令を割り当てるんです。
gosubの場合、「gosub *ABC」でラベル「*ABC」にジャンプしました。
モジュールの場合、新規命令「ABC」で「#deffunc ABC」にジャンプします。
実際のプログラムをとりあえず書いてみると、サブルーチンの場合、
一方、モジュール命令の場合だと、
書くものは違ってきていますが、形としては一緒ですね。
それでは、#deffunc命令の書式から見ていくと「#deffunc 命令名 p1,p2…p8」となっています。
先ほど上のプログラムでは、命令名のABCしかありませんでしたがパラメータは最大で8個までOKです。
当然8個全部書く必要はなく、サンプルのように1つもなくても問題ありません。
パラメータとして、指定できる項目は「数値」「文字列」「変数(配列変数)」の3種類となっており、
#deffunc命令に数値パラメータを指定したい場合は「int」と書きます。
文字列を渡す場合は「str」で、変数の場合は「val」です。
intとかstrって前の講座で出てきた命令でしょ?
はい、その通りでございます。
なぜかは知りません。
命令と混同して紛らわしいと言われれようと仕様ですから従いましょう…。
注意が1点ありまして、数値以外の2つはパラメータ1もしくはパラメータ2しか渡せません。
つまり…
| OK | #deffunc TEST1 str , str , int |
| OK | #deffunc TEST2 val , int , int , int , int , int |
| OK | #deffunc TEST3 int , str |
| NG | #deffunc TEST4 str , int , val , int |
| OK | #deffunc TEST5 val , val |
| NG | #deffunc TEST6 val , str , str |
| NG | #deffunc TEST7 int , int , int , str , int |
| OK | #deffunc TEST8 int , int , int , int , int , int , int , int |
| OK | #deffunc TEST9 |
もし、命令名をABCとして各パラメータを指定させたければ下記の様にします。
また、追記しておきますと、
パラメータが「int」となっている数値の場合、無理に指定せずとも省略して問題ありません。
つまり、「#deffunc ABC int」の時は呼び出し側で「ABC」とするだけでも実行できます。
省略した場合は、内部で0と解釈されます。
省略できるといっても例えば「#deffunc ABC int , str」の場合、
「str」だけでいいから、と呼び出し側で「ABC "XYZ"」とするといったことはできません。
省略できるのは数値だけであってパラメータそのものを省略できないということです。
つまり上記の場合「ABC , "XYZ"」と指定する必要があります。
受け渡しの方法はコレで分かりましたね?
しかし、呼び出し元で例えば「ABC 777」と指定されたとすると、
どうすればモジュール側で指定されたパラメータは777だと判断できるかというと、mref命令を使用します。
ヘルプに「特殊なメモリを割り当てる」とあるように特別っぽくてとっつきにくいイメージがあります。
実際、私は初めてこの命令を使うとき非常に使いにくくて何度もヘルプを見た記憶があります。
書式は「mref 割り当てる変数,割り当てるメモリ内容」と一見普通っぽいものとなっております。
曲者はp2のメモリ内容で、指定するのは下記のいずれかになります。
| 値 | 対応するリソース |
| 0 〜 7 | 数値 |
| 16 , 17 | 変数(数値型) |
| 24 , 25 | 変数(文字列型) |
| 32 , 33 | 文字列 |
| 48 , 49 | 変数(数値型配列) |
| 56 , 57 | 変数(文字列型配列) |
| 64 | システム変数stat |
| 65 | システム変数refstr |
| 66 | VRAMデータ |
| 67 | BMSCR構造体(アクティブウィンドウ) |
| 96 〜 103 | BMSCR構造体(ウィンドウID0〜7) |
| 1024 , 1025 | PVAL構造体 |
ヘルプには対応するリソースで「ローカルパラメータ#1」や「#2」というような書き方がされており、
それについての説明がなかったため、コレを見たときに何のことを言っているのか理解に欠けました。
#deffunc命令で数値を指定するとき8個までいけると書きましたが、
「0〜7」の8個はこの8個のことを示しています。
数値を指定する時はこの「値0〜7のうちいずれかを指定してね」という意味ではありません。
#deffunc命令のp1の時はmrefのp1に0を、p2の時には1を…p8の時には7を指定しましょう。
#deffunc命令に数値以外は2つまでしか指定できないと書きました。
上の表にあるように、#deffunc命令のp1が数値型変数の場合、数値と同じ様に16を指定しましょう。
同じ様に#deffunc命令のp2に文字列を指定する場合は33といった感じで…。
変数の時、普通の変数と配列変数が別々に用意されています。
コレは何を表しているのかと言うと、通常の変数指定の場合、1要素しか送られません。
HSPでは変数の定義をせずに使用した場合でも要素が16ある配列変数として扱われます。
通常の変数というのはdim,sdim命令で要素を1つにして使うという意味ではなく、
変数が配列であっても1つ目の要素(要素0)しか送られないということです。
配列変数で送った場合、すべての要素が送られます。(動きとしてdup命令と同じ)
さて、64・65・66・67・96〜103はどのパラメータに対応しているかが書いていません。
コレは、#deffunc命令でパラメータとして送らなくてもモジュール内部で使用できることを意味します。
64は、命令を使用した結果のステータス値として以前からよく使われていたシステム変数statです。
同じく65は、文字列型の結果を得る為に使われていたシステム変数refstrです。
この2つのシステム変数が使えるというのがどういうことかと言うと、
今回新しく作成する命令の結果として自分でもシステム変数に代入できるということです。
例えば、モジュール命令内で処理が成功したことを呼び出し元に返したい場合に
statに指定コードを入れてあげるとかができるわけですね。
66のVRAMデータは何かと言うと、ウィンドウ内画像データとあります。
これはウィンドウ内に picload命令で読み込んだ画像の情報に関するものと言う意味ではなく、
ウィンドウの各ピクセル(ドット)のRGB値を配列として持っています。
任意の位置の色要素を返すpget命令がありましたけど、それの全ピクセル版と思ってください。
コレを扱うには入門レベルを超えてしまいますのでココでは以上の説明だけに留めておきます。
どんな風に扱うのかが知りたい方はTipsにあるものをご参照ください。
67と96〜103はBMSCR構造体、とあります。
画像ではありませんが、コレもHSP内部(指定ウィンドウ)のデータを扱うためのものです。
ビットマップ、パレット、スクロール、フォントやオブジェクトに関する情報が詰め込まれています。
しかしVRAMと同じく高度ですのでココでは説明しません。
詳しくはdocsフォルダのHSPDLL.HTMやTipsをどうぞ。
1024,1025は#deffunc命令のパラメータ1と2に対応していますが何でしょう?
コレは、#deffunc命令のパラメータ1や2で指定した変数の情報が入っています。
指定変数が現在数値・文字列のいずれの型であるか、サイズはどのくらいか等を知ることが出来ます。
同じくココで説明しませんが、興味がある方はTipsをご覧ください。
#module
#deffunc bold str
mref moji,32 ; 文字列を指定
font "", 14, 1
mes moji
return
#global
bold "太字にして表示するテスト"
stop
#deffunc命令の呼び出し側を変数指定する場合で1点補足をしておきましょう。
変数をパラメータとして指定する場合、実は受け側が「val」でなくてもOKなんです。
#deffunc側が「int」でも、呼び出し側で数値の入った変数を指定すれば動くんです。
#module "atai_watashi"
#deffunc numtest int ; 受け取るのは数値
mref num,0
num++
mes "モジュール内:" + num
return
#global
suuchi = 5
numtest suuchi ; 変数を渡す
mes "モジュール外:" + suuchi
stop
これだけだと「val」と書くと変数のみ渡せて「int」とすると変数でも数値でもいける。
「int」の方が2パターンいけるようになって便利じゃん、と思えますね。
同じ様に見えますが、変数をパラメータとする時「val」と「int」で変わってくる点があります。
それは変数の「参照渡し」となるか「値渡し」となるかという違いです。
「参照渡し」というのは変数自体(厳密にはポインタ)を渡します、というもので
「値渡し」というのは変数の中身だけを渡すということです。
上記の違いにより実際はどう異なるのかと言うと、モジュール内でソレを扱った後に違いが出てきます。
先ほどのサンプルでは変数の値渡しでした。
モジュール内で受け取ったパラメータに1加算していますが、
あくまでパラメータの数値に1を足して表示しているだけあり、
モジュール通過後のメイン側での変数の値はモジュールに送る前のままです。
しかし、コレを下記のように「変数渡し」とすると、モジュール通過後の変数の値は1加算されていますね?
#include "atai_watashi"
#deffunc numtest val ; 受け取るのは変数
mref num,16
num++
mes "モジュール内:" + num
return
#global
suuchi = 5
numtest suuchi ; 変数を渡す
mes "モジュール外:" + suuchi
stop
コレは変数を渡しているので、変数に1を足されればメイン側でも1足された状態になるのです。
使用するときはこの違いをよく把握し、適した方を使いましょう。
次は簡単な命令ですが紹介する章がなかったのでココで説明いたします。
パソコンゲームではたまに起動するとパソコンの解像度が勝手に変更されるものがありました。
HSPでもchgdisp命令で640*480ドットのみ変更ができます。
解像度を統一したときに役に立つことでしょう。
書式は「chgdisp パラメータ」でパラメータに0を指定すると、chgdisp命令実行前の解像度となります。
1にすると640*480ドットのフルカラーモード(ウィンドウ内ではなくディスプレイ全体)となり、
2でパレットモードの640*480ドットとなります。
3は640*480ドットの現在と同じカラーモードとなります。
パレットモードに変更すると、例えウィンドウがフルカラーウィンドウでも256色しか表示されません。
640*480ドットのサイズのままHSPを終了すると
元のサイズに自動で戻りますので戻し忘れても問題はありません。
何らかの問題が生じて変更に失敗したときにはシステム変数statに0以外の値が入ります。
カラーモードの変更に失敗した場合は1が入ります。
解像度の変更に失敗すると2が入ります。
chgdisp 2
if stat > 0 : dialog"変更に失敗しました" : end
mes "終了すると戻りますが\n他のウィンドウの位置やサイズがおかしい場合があります\n注意しましょう"
stop
最後にexec命令を説明します。
run命令と違い、axファイル以外のあらゆるファイルを実行することができます。
書式は「exec "実行するファイル",実行モード,"コンテキストメニュー"」です。
p1のファイル名はcurdir以外にwindirもパスを省略してファイル名だけ書いても実行することができます。
ファイルがexeファイルでなくデータファイル(テキストや画像など)の場合、
どのファイルで開くかをファイル名の前に書くこともできます。
例えばasファイルをメモ帳で開く場合は「exec "notepad common\\hspext.as"」。
パスに半角スペースが入っている場合はFAQにも書いていますが、ダブルクォートで囲む必要があります。
ダブルクォートだけでなくちゃんとエスケープしてくださいね。詳しくはFAQで。
p2のモードに0または省略するとexecを実行してもHSPウィンドウも裏(?)で進行しています。
1を指定するとHSPウィンドウはアクティブになるまで実行を中断します(タスク待ち)。
2を指定するとHSPウィンドウを最小化し実行を続けます。
16を指定すると関連付けられたexeファイルで実行されます。
32を指定すると関連付けられたexeファイルで印刷されます。
p3のコンテキストメニューはレジストリに登録されているアクションをします。
たとえば「"properties"」で実行せずにプロパティを表示することができます。
コンテキストメニューを指定するとp2のモードの16と32の指定ができなくなります。
例として簡易ランチャーの作成をしてみましょう。
title "簡易ランチャー"
width 200, 75
objsize 200, 25
button "電卓", *start
button "メディアプレイヤー", *start
button "HSPBC掲示板", *start
stop
*start
if stat==0 : exec "calc"
if stat==1 : exec "C:\\Program Files\\Windows Media Player\\wmplayer.exe"
if stat==2 : exec "http://bbs1.nazca.co.jp/13/hspbcbbs/",16
とりあえずHSP2.55時代の講座としては以上で完結となります。
次章からはHSP2.6向けのものとなっていきます(初めは2.55の復習から)。