[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
今回は、変数は変数でもただの変数ではない配列変数を紹介したいと思います。とはいっても、全然難しいことではないので安心してください。
例えば、シューティングゲームを作るとしましょう。当然、敵が動いて襲ってくるはずです。「敵が動く」ということは、1コマ1コマ敵の座標が変わっているということです。アニメーションの時にやったように、敵の座標を変数で管理して、1コマ1コマ値をちょっとずつ変えながら描画すれば出来そうです。ここで具体的に敵の座標を
tekix, tekiy
という2つの変数で管理するとします。
そのシューティングゲームには1匹の敵しか出てこないなら上でいいでしょう。しかし恐らく、一般的なシューティングゲームには、敵は少なくても3匹は出てくるはずです。と言うことで変数を増やして
tekix1, tekiy1, tekix2, tekiy2, tekix3, tekiy3
としましょう。(一番最初の文字でなければ変数の名前に数字が使えます。)
このシューティングゲームを作っている間に更に2匹欲しくなってきました。やっぱり敵は多いに越したことはないですよね。と言うことで変数をもっと増やして
tekix1, tekiy1, tekix2, tekiy2, tekix3, tekiy3, tekix4, tekiy4, tekix5, tekiy5
としました。
ここの辺りで気付いた人は入ると思いますが、上の方法では非常に面倒です。敵の数を増やすたびに変数の数も増えていくと言うのは不合理です。しかも、この場合では、敵によって変数名が違うため、例えその敵が同じ種類で同じ動きをするとしても、それぞれに対してプログラムを個別に書かなくてはなりません。
変数の1番最後の数字が変わっているだけなのに・・・
ここで非常に便利なのが配列変数です。これを使うと
tekix, tekiy
という、たった2つの変数名で、いくつもの敵の座標を管理することが出来ます。
配列変数とは、普通の変数の集まりです。その変数の集まり全体に変数名があり、それぞれには識別するために番号が付けられています。その、それぞれを識別するための番号を「添え字」と言います。
呼び方のシステムとしては、駅のコインロッカーによく似ています。例えばある駅に、「改札口前ロッカー」と「売店横ロッカー」があるとします。それぞれ、いくつかのロッカーの集まりです。通常、ロッカーには通し番号が付けられていますよね?それで、「改札前ロッカーの3番」とか、「売店横ロッカーの5番」とか言う風に呼べるわけです。
配列変数も非常にこれと似ています。「改札前ロッカーの3番」という呼び方の、「改札前ロッカー」の部分が配列変数の変数名にあたり、「3番」の部分が配列変数の添え字にあたります。また、1つ1つのロッカー(1つ1つの変数)を要素といいます。つまり、改札前のロッカーが全部で50個あった時、要素数は50個である、と言う風に言います。
プログラム上でどのように使うかと言うと
変数名(添え字)
のように使います。ちょっとだけ具体的に使ってみましょう
// 配列変数を作成
dim tekix, 3
dim tekiy, 3
// 配列変数にそれぞれ値を代入
tekix(0) = 100
tekiy(0) = 100
tekix(1) = 200
tekiy(1) = 200
tekix(2) = 300
tekiy(2) = 300
// それぞれの位置に円を描画
repeat 3
circle tekix(cnt) - 5, tekiy(cnt) - 5, tekix(cnt) + 5, tekiy(cnt) + 5
loop
実行すると小さい円が斜めに3つ表示されます。
プログラムを最初から見ていきましょう。まず
dim tekix, 3
dim tekiy, 3
があります。dim命令が使われていますが、これはそれぞれ、「tekixという要素数が3の配列変数を作れ」「tekiyという要素数が3の配列変数を作れ」といっています。実はこのdim命令をつかって
dim 変数名
と言う風に要素数を指定しなければ、普通の変数を作ることが出来ますが、今までは省略してきました。この命令を使わなくても、最初に変数に代入した時にHSPが勝手に作ってくれるからです。配列変数でもこの命令を使わなくとも、最初に代入した時に配列変数を作ってくれます。つまり、この2行は無くてもとりあえず問題ありません。こういう命令があることを示すために書いておきました。
つぎに、
tekix(0) = 100
tekiy(0) = 100
tekix(1) = 200
tekiy(1) = 200
tekix(2) = 300
tekiy(2) = 300
とあります。これは、tekix、tekiyという配列変数の各要素に値を代入しています。普通の変数と違うのは、何番目の要素かを示す添え字があるところです。ここで注意して欲しいのは、要素の番号は0から始まる、と言うことです。よってこの場合、要素数が3であるため、添え字に指定できるのは、0、1、2の3つです。
そして、注目して欲しいのはこの部分です。
repeat 3
circle tekix(cnt) - 5, tekiy(cnt) - 5, tekix(cnt) + 5, tekiy(cnt) + 5
loop
repeat命令とloop命令で、circle命令を3回繰り返しています。このcircle命令ではtekix、tekiyの配列変数の要素の値を利用して円を描画するわ訳ですが、添え字の部分に「cnt」とかかれています。これはシステム変数の1種で、repeat-loop命令で何回目の繰り返しか、と言う値が入っています。つまり、一番最初の繰り返しでは0、次の繰り返しでは1、その次の繰り返しでは2、・・・と言う風に順次変化していきます。よって、3つの円がそれぞれの位置に描画されます。
ここで味噌なのが、添え字には普通の命令のパラメータと同じように、変数や、計算式を入れることが出来る、と言うことです。これが、普通の変数の名前の最後に数字を付ける時との大きな差で、配列変数を利用する時の最大の利点です。上のプログラムの描画部分のような書き方は、ゲームを作る際にたくさん出てくると思うので是非身につけて下さい。
今回の例はあまり面白くないかもしれませんが、これから配列変数は割と出てくると思います。いろいろ、配列変数で遊んでください。
今回はマウスを簡単に使ってみたいと思います。
マウスのボタンの入力は、前回触れたgetkey命令で取得できます。キーコードは、「HSP講座8」の表のとおり、左ボタンが1、右ボタンが2です。
キーボードと違うのは、マウスの座標の取得ですが、それは、システム変数の値を利用することで、簡単に取得できます。
システム変数とは、変数の一種です。今まで使ってきた、自分たちで初期化して使う変数とは違い、HSPのシステムであらかじめ用意されている変数のことです。システムが用意する変数であるため、変数の名前はあらかじめ決まっています。
例えば、「mousex」というシステム変数には、マウスカーソルのx座標が入っています。また、同じように「mousey」というシステム変数に、マウスカーソルのy座標が入っています。
実際に使ってみましょう。
次のプログラムは、マウスの左ボタンを押している間、カラフルで大小さまざまな円がマウスカーソルの位置に描画され、右ボタンを押すと、画面内が白でクリア(塗りつぶし)されると言うものです。
// 乱数初期化
randomize
repeat
// マウス左ボタン検出
getkey lclick, 1
// マウス右ボタン検出
getkey rclick, 2
// 条件:左が押されていれば
if (lclick == 1) {
// 色:ランダム
color rnd(256), rnd(256), rnd(256)
// 半径:1から100の間でランダム
r = rnd(100) + 1
// (mousex, mousey)中心の円描画
circle mousex - r, mousey - r, mousex + r, mousey + r
}
// 条件:右が押されていれば
if (rclick == 1) {
// 色:白
color 255, 255, 255
// 画面内塗りつぶし
boxf
}
wait 5
loop
if文の色をちょっと変えてみました。見やすいでしょうか?
実行すると、マウスを押している間、ずっと円が描画されると思います。円と次の円が描画されるまでの時間が、「wait 5」です。(実際は、他の処理も多少時間をとっていますが)
プログラムの説明ですが、getkey命令付近は、大体分かると思います。前回説明したとおりです。
今回は色と半径をランダムにしています。「r = rnd(100) + 1」の「+1」は「r」が0になるのを防ぐ役割があります。「+1」がなければ、rの範囲は0~99ですが、「+1」することで1~100となっています。
問題のマウス座標ですが、円描画の行を見てください。
circle mousex - r, mousey - r, mousex + r, mousey + r
となっています。このように、「mousex」「mousey」というシステム変数も、代入さえしなければ、普通の変数のように利用することが出来ます。この「mousex」「mousey」には、常に、その時のマウスの座標が入っているため、マウスを押しながら移動させたりしても円はマウスの位置にちゃんと描画されます。
とても簡単だとは思いませんか?ここまでやってくれば、簡単なペイントソフトみたいなものは出来そうな気がしますね。
今日は、玉をキーボードで動かしてみようと思います。
キー情報は、getkey命令で取得します。getkey命令は、ある指定したキーが、押されている状態か押されていない状態かを取得する命令で、
getkey 変数, キーコード
と言う風に使います。
キーコードとは、キーボードのキー一つ一つに割り振られた番号のことで、次のようになっています。
キーコード : 実際のキー
------------------------------------------
1 : マウスの左ボタン
2 : マウスの右ボタン
3 : キャンセル([CTRL]+[BREAK])
4 : 3ボタンマウスのまん中のボタン
8 : [BACKSPACE](PC98の[BS])
9 : [TAB]
13 : [ENTER]
16 : [SHIFT]
17 : [CTRL]
18 : [ALT](PC98の[GRPH])
20 : [CAPSLOCK]
27 : [ESC]
32 : スペースキー
33 : [PAGEUP](PC98の[ROLLDOWN])
34 : [PAGEDOWN](PC98の[ROLLUP])
35 : [END](PC98の[HELP])
36 : [HOME](PC98の[HOMECLR])
37 : カーソルキー[←]
38 : カーソルキー[↑]
39 : カーソルキー[→]
40 : カーソルキー[↓]
48~57 : [0]~[9](メインキーボード)
65~90 : [A]~[Z]
96~105 : [0]~[9](テンキー)
112~121 : ファンクションキー [F1]~[F10]
(「HSP HELP Browser Ⅱ」 から引用)
この数値をgetkey命令に指定すると、押されている状態であれば変数に1が、押されていない状態であれば変数に0が代入されます。
実際に使えば分かると思います。ちょっと長いですが次のプログラムを実行してみてください。
// 初期位置
x = 100
y = 100
// 移動スピード
sp = 10
// 半径
r = 10
repeat
// キー情報取得
getkey hidari, 37
getkey ue, 38
getkey migi, 39
getkey sita, 40
// 移動
if (hidari == 1) {
x -= sp
}
if (ue == 1) {
y -= sp
}
if (migi == 1) {
x += sp
}
if (sita == 1) {
y += sp
}
// 描画始め ++++++++++++++++++
redraw 0
// 背景
color 0, 0, 0
boxf
// 玉
color 255, 255, 255
circle x - r, y - r, x + r, y + r
redraw 1
// 描画終わり ++++++++++++++++
wait 3
loop
カーソルキー(十字キー)を押すと、その方向に玉が動くと思います。
最初に
x -= sp
という書き方に触れておきますが、これは今まで使ってきた、
x = x - sp
と同じことです。つまり、xの値をspの値だけ減らす、と言う意味です。スマートに見えるので書き換えました。
今まではspの部分は定数を用いてきましたが、変数にすることで、「アイテム取得でスピードアップ!」と言うような処理が出来ます。今回はしていませんが、今後ゲームを作る際に、こういう書き方が必要になると思うので、こうしておきました。他に、spの代入する値を変更するだけで、spの部分の値を一括変更できるというメリットもあります。
キーの情報の取得はこの部分です。
getkey hidari, 37
getkey ue, 38
getkey migi, 39
getkey sita, 40
37,38,39,40と言うキーコードは、上の表で見ると、カーソルキーの左、上、右、下であることが分かると思います。
つまり、カーソルキーが押されているか押されていないかの情報が、それぞれ、hidari、ue、migi、sitaと言う変数に代入されることになります。
そして、その変数の値を利用しているところがここです。
if (hidari == 1) {
x -= sp
}
if (ue == 1) {
y -= sp
}
if (migi == 1) {
x += sp
}
if (sita == 1) {
y += sp
}
ここで、if (なんたら) { かんたら } という文が出てきました。この文をif文と言います。ifと言うのは英語で「もしも~ならば」という意味を持ちますが、プログラム上のif文もそうです。もし()内の条件が満たされていれば、{}内の処理をします。逆に()内の条件が満たされていなければ、{}内の処理を行いません。
ここで==は左辺と右辺が等しい場合、という条件を示します。つまり、それぞれ、hidari、ue、migi、sitaの値が1、つまりキーが押されている状態であれば{}内の処理を行うというものです。{}内の処理はそれぞれ、x座標、あるいはy座標を変化させる処理となっているので、カーソルキーを押すと、円が移動する、ということになります。
xを増やすか減らすかという符合の問題は、x座標の正方向が右、y座標の正方向が下、と言うことを考えれば分かると思います。
なんだかゲームっぽくなってきたと思いませんか?次はマウスでも触ってみるかもしれません。
あと、HSP HELP Browser Ⅱは、スクリプトエディタのメニューのヘルプ>HSP命令リファレンスを開く、から起動することが出来ますので、命令の詳細が知りたい時や、どんな命令や関数があるか知りたい時は開いてみてください。
これまでは、プログラムを実行する度、毎回同じ処理をしていました。
そんなプログラムにはそろそろ飽きてきたかもしれません。
ということで、とりあえず乱数を使ってみようと思います。
乱数とはランダムな数のことです。サイコロ振った目の数みたいなもんです。
ただ、パソコン内でサイコロを振っているわけではないので、
プログラムで使えるのは
計算から求められた擬似的な乱数です。
その前に、関数の説明をしておこうと思います。
(乱数と同じ”数”がついていますが全く関係ありません。)
特に難しい話ではないのですが、中学や高校の数学で、
y = f(x) とか y = g(x) とか、あるいはf(x)の中身を具体的に書いて、
y = 2x とかいう関数を見たことがあるかと思います。
プログラム上の関数もこんな感じです。
xの値を与えることで、f(x)の値が決まる、というものです。
このxのことを命令と同様にパラメータと言いますが、
このパラメータの数は1つとは限りません。
x, y, zの値を参考に、g(x, y, z)の値が決まる、というのもあるでしょう。
実際に使ってみましょう。
// 半径
r = 5
// 乱数の初期化
randomize
repeat
// ランダムに位置を決める
x = rnd(640)
y = rnd(480)
// 円の描画
circle x - r, y - r, x + r, y + r
wait 1
loop
実行したら、黒い点が次々に表示されます。
もう、大体のプログラムの流れは分かると思うので割愛します。
乱数を使う時は、使う前にrandomize命令を置いて下さい。乱数が初期化されます。
これをしないと、乱数が毎回同じ、つまり乱数でなくなってしまいます。
それをしたあとに、
x = rnd(640)
y = rnd(480)
のところで、乱数を作っています。
rnd関数が乱数を発生させる関数で、数値のパラメータを1つとります。
上のプログラムの場合、xに0から639までの数(640通り)の中のどれか、
yに0から479までの数(480通り)のどれかがランダムで代入されます。
前にも言った通り、ウィンドウのサイズはデフォルト(標準初期値)で640×480なので、
rnd関数によって決められた円の中心座標は、画面内のどこかの点です。
乱数の使い方は大体分かったでしょうか?
ゲームでも、
降り注ぐ岩の位置とか、
的の出てくる微妙なタイミングとか
煙球のランダムな色など
色々使えるとおもうので、覚えておきましょう。
次回はキーボードの情報を利用する予定です。
ここから、面白くなってくる可能性があります。
前のプログラムでチカチカしていた理由。
それは、背景を塗りつぶした瞬間が見えてしまっていた、ということです。
背景を塗りつぶした瞬間と、その後に円を描画した絵が交互に映ったため、チカチカ見えたのです。
次のようにプログラムを変えましょう。
// 変数初期化
x = 100
y = 100
r = 10
repeat
// 描画モード→0
redraw 0
// 背景塗りつぶし
color 0, 0, 0 // 黒
boxf
// 円の描画
color 255, 255, 255 // 白
circle x - r, y - r, x + r, y + r
// 描画モード→1
redraw 1
// x座標を5増やす
x = x + 5
// 50ms待つ
wait 5
loop
redraw命令が新しく加わりました。redraw命令は描画モードを変更する命令です。
描画モード0は、描画命令が実行されても、実際の画面には反映されず、仮想画面上の描画にとどまる、と言う状態です。
一方描画モード1は、描画命令が実行されたその時に、実際の画面に反映されるというモードです。
また、描画モード1にした瞬間、それまで仮想画面にあったイメージが実際の画面に反映されます。
と言うことは、いろいろ描画する前に描画モードを0にしておいて、全ての描画が終わったところでモードを1にすれば、描画の過程は画面に反映されず、結果のみが見えるということになります。これで、ちらつきが解決されます。
これから、いろいろプログラムを書いていく上で、呪文のように毎回書くことになります。大切なことなので、是非覚えておきましょう。