まず、HDL(HSP Document Library)はご存じですか?
HSPエディターでf1、もしくはメニューのヘルプ→HSP命令リファレンスを開く から開くことが出来ます。
もしわからない命令があったらそこで検索することをお勧めします。
もしHDLに無い場合はインターネットで「HSP 検索したい命令」で検索するといいでしょう。
ではプログラムの解説を始めます。
#include "winmm.as"
これはtimeGettimeを使う為にwinmm.asというファイルをインクルードしています。
winmm.asとは通常のHSPと同じコートが書かれており、メインのソースコードに直接コピペして書いても構いません。
ですがそうすると無駄に長くなったり見づらくなったりするので、適度にインクルードを使う事で可読性をあげています。
winmm.asにかかれている内容ですが、簡単に言うと外部DLLを呼び出すコードが大量に書かれています。
この中に今回使うtimeGettimeが含まれています。
DLLとは主にC言語で書かれたプログラムを他の言語でも使えるようにしたものです。
TimeGetTimeの詳しい説明は後でします。
PicSizeX=80//画像のサイズ
PicSizeY=70
LisX=10//マス目の数
LisY=3
この行で、今後頻度に使う値を変数に代入しています。
各場面で数字で描くよりも変数で書いたほうが可読性が高く、
後から数字を変えるのも楽です。
ちなみに似たようなもので、#constという命令があります。
詳しい説明をHDLを見てください。
変数はPicSizeX、PicSizeYが画像のサイズです。
LisX、LisYは列の数です。
buffer 1,PicSizeX*LisX,PicSizeY*LisY//buffer
HSPにはウィンドウの種類が主に2つあります。
1つは通常のScreen命令で作成できる画面。
もう1つがbuffer命令で作成できる仮想画面です。
仮想画面は通常の画面とは違い、表示されません。
従って何度もソフト内で使う画像を保存する時に使用します。
PicLoadでいいじゃないか!と思うかもしれませんが、
PicLoadは記録ドライブ(HDDやSSD)から直接読みだしているので、
何度も使うと記録ドライブに負担をかけ、更に時間もかかります。
従ってbufferに1度読み込んでおき、必要に応じてメイン画面にコピー表示した方が遥かに楽なんです。
Font "メイリオ",25//今回は画像を用意するのが面倒だったので適当に文字を表示します。
repeat LisX
ct=cnt
repeat LisY
Color 156+rnd(100),156+rnd(100),156+rnd(100)//色を指定
boxf ct*PicSizeX,cnt*PicSizeY,ct*PicSizeX+PicSizeX,cnt*PicSizeY+PicSizeY//単色で塗り潰し
Color 0,0,0
pos ct*PicSizeX,cnt*PicSizeY+PicSizeY/2.0-25//位置を設定
mes ""+ct+"x"+cnt+""//文字を描画
loop
loop
ここは、本来なら画像を表示するので、もっと短くなります。
Font "メイリオ",25でフォトを指定。
その次、ループが二重になっていますよね。
恐らく特に分かりづらかったのがここだと思います。
repeat~loopは繰り返す命令です。
「repeat 繰り返したい回数」と書き、繰り返す回数を指定します。
今回はrepeat LisXと書いています。
LisXには10が代入されているので、10回ループすることになります。
其の次の行でct=cntと書いていますね。
cntとはシステム変数で、ループした回数が代入されています。
cntの値をctに代入しています(理由はもう少し後に説明します)
その後またrepeat~loopを使っていますよね。
(今回は19~25行のループを1回目のループ、21~24行の2回目のループを呼びます)
これは1回目のループはX列、2回目のループはY列の描画の為です。
2回目のループの中でcntの値を取得すると、2回目のループ回数が取得されてしまいます。
従って1回目のループ回数も取得したい!という場合は2回目のループに入る前にct=cntと書き、システム変数から通常の変数に値をバックアップしておかなければいけません。
repeat 5
ct=cnt
repeat 5
pos ct*20,cnt*20:mes "●"
Dialog "ct:"+ct+"\ncnt:"+cnt+""
loop
loop
このプログラムを実行してみてください、ctとcntの変化がよくわかると思います。
ループ内にあるColor、rnd、boxf、pos、mesはHDLを見れば詳しい説明が乗っているので説明は省略します。
Screen 0,PicSizeX*LisX,PicSizeY*LisY//メインウィンドウ
ここでメインウィンドウのサイズを決定しています。
repeat LisX
ct=cnt
repeat LisY
pos PicSizeX*ct,PicSizeY*cnt:gcopy 1,PicSizeX*ct,PicSizeY*cnt,PicSizeX,PicSizeY//画像を表示
pos PicSizeX*ct,PicSizeY*cnt+PicSizeY-25:button gosub ""+ct+"x"+cnt+"",*Jump//ボタンを設置
loop
loop
ここでループが二重に成っているのは先ほど説明したのと同じ理由です。
重要なのが22行目~23行目です。
今思うと少し書き方が悪かったですね。
間に:が入っていますが、これは命令を続けて書くためです。
意味としては改行と同じ効果です。
適度に:を使うことでコードの可読性が上がります。
ですがHSP始めた時はこれを使われると非常にわかりづらいですよね。
(少なくとも自分はそうでした。)
posはHDLに書いてあると通り、描画する位置を決定します。
psoに対応している命令・対応していない命令があるので、注意が必要です。
その次のgcopyは仮想画面からメイン画面に画面の一部をコピーする命令です。
gcopyにはパラメーター(引数)を5つ指定でき、それぞれの説明はHDLに書いています。
次の行のposはbuttonの描画位置を決めるためです。
buttonとはボタンを描画する命令のことで、
ボタンをクリックすると指定したラベルにジャンプします。
基本的には、
button "ボタンに表示するテキスト",*ラベル
という書き方をします。
ですがこのプログラムではbuttonとp1の間にgosubと書いていますよね。
これはサブルーチンジャンプというもので、書かない場合は通常のラベルジャンプを行います。
通常のラベルジャンプは1度ジャンプしたらそれっきり。
ですがサブルーチンジャンプを行うと、ジャンプ先でreturnと書くとジャンプ元に戻ってきます。
なぜ戻す必要があるのか?という説明はこの後に説明します。
まずはジャンプ先で何をやっているのかを説明します。
ジャンプ先は39行目の
*Jump
Dialog ""+stat+"番目のボタンをクリック!"
オブジェクトID=stat
return
この部分です。
まずDialogでクリックしたボタンの番号を表示し、オブジェクトIDにstatの値を代入します。
statにはクリックしたボタンのオブジェクトIDが代入されています。
オブジェクトIDとはオブジェクト(ボタンや入力ボックス等)を設置すると自動的に割り振られるもので、
0から順番に割り振られます。
このオブジェクトIDを記録しておけば、どのボタンがクリックされたのかがわかります。
そしてオブジェクトIDを変数に代入した後、returunでジャンプ元に戻ります。
timeGetTime//PCが起動してからの時間を取得
基準時間=stat//記録しておく
オブジェクトID=-1
TimeGetTimeを使うと、statというシステム変数にPCが起動してからの時間が代入されます。
単位はms。つまり1000で1秒です。
システム変数とは様々な命令が共通で使用する変数のことで、システム変数は複数あります。
主に使うのはcnt、stat、start、ginfo系等です。他にも大量にあるので、ここで全て説明することは出来ません。
HDLで「システム変数」と検索してみてください。
次の行で基準時間という変数にstatの値を代入しています。
次、オブジェクトIDという変数を-1にしていますよね。これは次のループ内の説明で説明します。
次のループは無限ループで、経過時間をカウントする為です。
1ループ毎にTimeGetTimeを使い、最新のPCが起動してからの時間を代入します。
この時取得した値から基準時間の値を引くことで、経過時間がわかる、というカラクリです。
何度も引き算で計算するのは可読性が低くなるので、一旦経過時間という変数に経過時間を代入します。
title ""+(経過時間/1000)+"秒"でタイトルに経過時間を表示しています。
その次のifが重要です。
命令の意味は説明せずともわかると思いますがifとは条件分岐の命令です。
日本語で言うと「もしも」ですね。
ここでは「もしもオブジェクトIDが-1以外だったらループを抜ける」と書いています。
!がそれ以外、という意味です。
ボタンがクリックされると、オブジェクトIDという変数にクリックしたボタンのオブジェクトIDが代入されます。
オブジェクトidは0から始まるので、必ず-1以外になります。
つまり-1以外ならボタンをクリックしたという事です。
ではなぜわざわざサブルーチンジャンプにしたのかというと、ループは必ず指定回数ループして抜けるか、
breakで抜ける必要が有る為です。
もしただのラベルジャンプだと、ループが正常に終われないまま抜けるので、そのうち「サブルーチンやループのネストが深すぎます」というエラーが発生します。
詳しくは以下のスレッドを見てください。
http://hsp.tv/play/pforum.php?mode=pastwch&num=4721
その次のifは経過時間が1万ms、つまり10秒以上になったらループを抜けるというものです。
つまり制限時間ですね。
説明は以上です。わからないことがあったら気軽に聞いてください。
どの部分がどうわからないかを書くと、回答する側としても回答しやすくなります。