テーブルで GO!(前編)

(New:1997/9/19)
プログラミングにおけるテーブルというものについて、前編と後編に分けて書きました。
テーブルとは、あらかじめ固定されたデータの並びのようなものです(かな?)。 テーブルを用いることにより、プログラムを高速化したり、スマート(smart)にしたりできます。

※ smart:(形)利口な;しゃれた;機敏な (出展:プロシード英和辞典(福武書店))

この前編ではキー変換テーブル、計算のテーブル化、三角関数のテーブル化について取り上げ、後編ではレーダー法というものについて取り上げます。

※本文は基本的に BASIC 向けですが、テーブルに関する基本的な考え方は使用言語を問いません。 本文では、テーブルは BASIC の配列として用意していますが、例えばアセンブリ言語なら DEFB(DB) や DEFW(DW) などの擬似命令を用いるなどすればいいと思います。

※このページのテキスト版(.txt)とサンプルプログラムをセットにした圧縮ファイルを用意致しました。 ぜひ、お手持ちの MSX でサンプルプログラムをお試し下さい。
→ ダウンロード

※このページに書かれているサンプルプログラムはブラウザの性能上、一部全角文字が使われていますが、それらは実際には半角文字であるとして見て下さい。


キー変換テーブル

例えばカーソルキー(レバー)の入力方向に合わせて、ゲームの自機を動かしたり、カーソルを動かしたりしたいとき、キー変換テーブルを用いるとプログラムがスマートになります。
キー変換テーブルとは、カーソルキー(レバー)の入力方向毎に、x、y 座標の増分(マイナス含む)を収めた配列です。 これを用いれば、カーソルキー(レバー)の入力方向(0〜8)からすぐに、x、y 座標の増分が求められるというわけです。

サンプルプログラムでは、キー変換テーブルの x 座標分を配列 TX(st) (st:カーソルキー(レバー)の入力方向)、y 座標分を配列 TY(st) としています。TX(st)、TY(st) にはそれぞれ、カーソルキー(レバー)の入力方向が st のときの、x、y 座標の増加量が入っています。

サンプルプログラム1と解説


計算のテーブル化

例えば高速な処理を求められるような場所で、複雑な計算を行なったり時間のかかる関数を使うとき、その計算結果をあらかじめテーブルにしておくと高速になります。 具体的には計算・関数の入力を配列(テーブル)の添字とし、そこにその入力に対する出力(計算の結果)をあらかじめ入れておきます。 これを僕は「答えの作り置き」と呼んでいます。
配列の次元は入力する変数の数になります(サンプルでは1次元)。
この方法ではあまり広範囲の入力に対応できないことや、あまりきめ細かな入力に対応できないことが問題ですが(テーブル用の配列が巨大になる)、そうでない場合にはかなり有効だと思います。

サンプルプログラム2では、0〜255までの整数を順に入力とし、その平方根を SQR 関数とそれをテーブル化したものを用いて計算します。 そして計算にかかった時間を比較します。 結果はテーブル化した方が40倍以上速いはずです。
このテーブルでは入力が0〜255の整数に限定されてしまいますが、状況によっては使えるテクニックだと思います。
もちろん、他の関数や計算にも応用できることでしょう。

また、このサンプルでは、平方根テーブルをプログラムの始めの方で SQR 関数を用いることによって準備していますが、この準備も結局 SQR 関数を用いるために遅くなっているので、実戦(^^;)ではテーブルの中身(SQR の結果)をあらかじめ DATA 文やファイルにしてしまってもいいでしょう。 アセンブリ言語なら DEFB、DEFW 命令で用意するとかね。

サンプルプログラム2と解説


三角関数のテーブル化

先の「計算のテーブル化」の応用です。 三角関数も計算に時間がかかる関数ですから、十分テーブル化する価値があります。 ここで問題になるのは、どれくらい入力が細かいテーブルにするかということです。

例えば、少し前の市販シューティングゲームの画面を見ていると、敵弾は限られた方向しか飛ばないようです。 自機に向かって飛んでくるように見える敵弾も、限られた発射方向から、自機に最も近いところを通る方向を、何らかの方法で選択して飛ばしてくるに過ぎないようです。 ですから、特に昔のシューティングなどでは、状況によってはじっとしていても敵弾が当たらない、といった現象も起こるのだと思います。


敵弾は限られた方向しか飛ばない?

例えばアレスタ2やストライカーズ1945PLUSなどは、敵弾の発射方向は32方向しかないのではないかと思います(16方向しかないようなゲームもあったけど、いい加減狙いが不正確だと思います)。 だからというわけではありませんが、とりあえずここでは、sin、cos テーブルの入力(角度)は32方向分用意することにしましょう。 360度を0〜31の整数で表現するのです。
角度 n =((360÷32)× n )°=(((2×π)÷32)× n)rad
(n は0〜31の整数)
という感じです。

※でも、某バトル○レッ○や某いかりどんぱちなんかは、もっとたくさんありそう。前者なんか256方向くらいあるんじゃないだろうか。

サンプルプログラム3では、画面中央の水色の玉から、黄色い弾を発射します。 発射方向は全てで32方向で、その中からランダムに発射方向を決めます。 発射角度(発射方向)は画面下に表示されます。
y 座標は画面向きで、それに伴い、角度も時計周りに大きくなっていくことに注意して下さい。 つまり、発射角度が0のとき右向き、…、8のとき下向き、…、16のとき左向き、…、24のとき上向き、…になります。

サンプルプログラム2同様、sin テーブル、cos テーブルを計算で準備しているので、実戦ではテーブルの中身をあらかじめ DATA 文やファイルにしてしまってもいいでしょう。 アセンブリ言語なら DEFB、DEFW 命令で用意するとかね。
また、アセンブリ言語や C 言語などの場合は、sin テーブルか cos テーブルのどちらかだけを用意するのでも十分でしょう。 与えられた角度に、ある簡単な計算を施せば、同じテーブルからもう一方の値が求められるはずです(BASIC でもできなくはないけど、機械語ではほとんど気にならないであろう「計算」の時間の浪費が心配)。
(ヒント:cosθ=sin(θ+90°)。 マスク掛けも必要か)

サンプルプログラム3と解説


さて、サンプルプログラム3では、弾の発射角度をランダムに決めていましたが、後編では自機に向かう角度の求め方について書きます。

後編に続く)


MSXの適当手帳 MSX駅 西山駅