話を次に進める前に、少し寄り道して計算が便利になるクラスを紹介しておきます。 変数aの平方根、サイン、コサイン、座標計算……。非常に面倒な計算を簡単に行う事が出来るクラス、 それが今回紹介するMathクラスです。

Mathクラスに関して、公式リファレンス内で詳細は省かれているようなので、ここで補足説明をしておきましょう。

尚、この回に関しては読み飛ばしても構いません。必要になったら戻ってきてくださいね。

数学関数Mathの使い方

ここからは、吉里吉里/TJSに用意されているクラス(設計図)を使いながら、新しい機能の紹介をしていきます。 前提としてクラスの使い方が分かっている事が求められるので、 よく分からない方はクラスの項目を読み直してみてください。

今後もTJS2リファレンスを読みながら進めて頂ければ、より分かりやすくなります。 せっかく、開発者であるW.Dee 氏自らが作成された優秀なリファレンスがあるので、蛇足はしません。

Mathクラスはメンバー変数を持ちません。(持っていたとしても、参照されるべきではありません。) ですから、参照するのはメンバー関数とメンバープロパティのみです。 そして、Mathクラスは実物を作る必要がありませんので、次のように参照します。

Math.メンバー

例えば、円周率(パイ)を参照するには次のように書きます。

Math.PI

※PIは円周率を指すMathクラスのメンバープロパティです。

ところで、この書き方は不思議だと思いませんか? これまで、クラスというと単なる設計図なので実物を作りなさい、と説明してきました。 ところが、今回は実物を作る事無く、設計図自体を参照しています。

実は設計図(クラス)のメンバー自体を参照する事は可能なんです。 例えば System.inform() のように、Systemクラスの実物を作る事無く、 Systemクラスのメンバー自体を参照してきましたね。 次のプログラムも正常に動く事が確認できます。

class print
{
    function show(msg)
    {
        System.inform(msg);
    }
}
print.show("こんにちは!");
				

実物(オブジェクト)ではなく、クラスのメンバー自体を参照出来る。 これは後で重要になるので、覚えておいてくださいね。

この仕組みを利用すると、System.informの別名関数を簡単に作る事が出来ます。

var print = System.inform;
print("こんにちは!");
					

以前に説明したクロージャという機能と、クラスのメンバーの参照という方法を使っています。

ランダムに数を返す

ゲームではランダムな数(乱数)を必要とする場面が多くあります。 例えば、RPGである武器を持っていると3~5回攻撃できる武器。 カードゲームで、山札から1~3枚カードを引ける…といった具合です。

  • 0以上n以下の数を求める方法
  • min以上max以下の数を求める方法

ここでは、この二点を紹介します。

0~nの数を返す公式

まず、ランダムな数を取得するために、random関数を使います。 この関数は0以上1未満…つまり、0~0.999999…の値を返します。

Math.random()

0以上1未満の数を返すのだから、単純にnを掛ければ0以上n未満の数が取得できますね。 取得した数は実数ですから、intを使って整数にします。

int(Math.random() * n)

1を掛けると、intによる小数点切捨てで必ず0しか返って来ません。(1未満の数しか返さないからですね。) 2を掛けると、Math.random()が0.5以上の値を返した時に1になります。 同じく、2を掛けただけでは最高値は1.99999...なので2は超えません。

同様に考えると、3を掛けるとMath.random()が0.667..以上を返した時に2になります。そして3を超えない。

この事実から、Math.random()にnを掛けると、0以上n未満の数を返す事が確認できます。

という事は、n以下の数を返して欲しい場合、nに1を上乗せすれば良い事になります。

int(Math.random() * (n+1))

これで0以上n以下の数を求める公式の完成です。

最小値~最大値の数を返す公式

0以上n以下の数を取得するのに、次のように書きました。

int(Math.random() * (n+1))

この(n+1)の部分のnは希望数の最大値を指します。最小値は0ですね。 ここで、最小値を1にしたい場合、返された数に1を加算すれば、0を返される事はなくなりますね。

int(Math.random() * (n+1)) + 1

ただし、このままでは1~nの数が返ります。 Math.random() * (n+1)によって0~nが返されるからです。 ですから、nの数から最小値を考慮して、減算する必要があります。

int(Math.random() * (n-1+1)) + 1

※単純にnの値から最小値を減算し、最後に最小値を加算します。

これで1以上n以下の数を返す公式が出来上がりました。 わかり易くするために、最大値をMAX、最小値をMINとしてまとめます。

int(Math.random() * (MAX-MIN+1)) + MIN

必要であれば、これを関数として保存しておけば、任意の数の乱数を導き出すことが可能です。

数学が嫌いな方にとっては、分かりづらいかもしれません。 ただ、公式の意味を理解する必要はありません。 本質さえ分かっていれば、それで十分なのです。

三角関数

正弦、余弦、正接を計算する関数です。 「サイン」「コサイン」「タンジェント」という呼び方の方が分かりやすいでしょうか。 プログラムでは、シューティングゲーム等の角度計算に多く用いられています。

Math.sin(rad)…角度radの正弦

Math.cos(rad)…角度radの余弦

Math.tan(rad)…角度radの正接

radはラジアンという角度の単位を使用します。 よって、0~360という数値を指定しても、正しい結果は得られません。

角度ラジアンについて

TJSでは0~360度という角度を用いず、ラジアンという単位を利用します。 よって、正弦や余弦を計算する場合、角度はラジアンで指定する必要があります。

180度はラジアンのパイである事から、以下の式でラジアンに変換できます。

角度r * (2 * Math.PI / 360)

例えば、サイン90度は1ですが、ラジアンへ変換しないと値が狂います。

Math.sin(90)……0.89399...?

ラジアンを指定すると、1と表示されます。

Math.sin(90 * (2 * Math.PI / 360))

また、逆三角関数も扱えます。

Math.asin(rad)…角度radの逆正弦

Math.acos(rad)…角度radの逆余弦

Math.atan(rad)…角度radの逆正接

ラジアン変換を頻繁に行うのは面倒な事ですので、 次のような汎用関数を作っておく事をお勧めします。

function getRadian(x)
{
    return x * (2 * Math.PI / 360);
}
					

2数の逆正接

アクションゲーム等では、敵は自分をめがけて突進してきたり、 ちゃんとこちらを向いて、正確な角度で弾を発射してきます。不思議ですねぇ。 今回は、ある座標を基点として、ある座標への角度を出す関数を紹介します。

まずは、以下の図をご覧ください。

atan2_graph.png(7120 byte)

このx軸を基点として、座標x,yまでの角度pを計算したい場合、以下の関数が使えます。

Math.atan2(y, x)

数学的に言うと、直交座標を極座標へ変換を行ってくれます。

math_CtoP.png(11214 byte)

直交座標とは、点Pを原点からの縦横の距離で表すものです。x=7,y=5である場合、点Pは(7,5)と表現できます。

極座標とは、原点から点Pまでの距離と、x軸を基点とした点Pへの角度で、点Pを表すものです。atan2はこの角度を計算出来ます。

※角度が分かれば距離が分かりますし、xy座標が分かれば角度が分かる…という三角比の考え方を利用したものですね。

※xy座標の引数の順番に注意。最初にy座標、次がx座標です。順番を間違えることが多いので注意しましょう。

例えば、味方のオブジェクトをmy、敵をemyとした場合、 各座標をxyを減算してatan2に与えてあげれば、双方の角度を求める事が可能です。 (どちらを原点にするかによって、減算される側は変わりますので注意してください。)

Math.atan2((my.y - emy.y) , (my.x - emy.x)

本ページでは、実際の利用法については割愛させていただきます。 あまり細かく説明すると入門では無くなってしまいますし、 プログラムとは別の話になってしまうからです。

  • ラジアン値を(2*Math.PI/360)で割れば、0~360度といった角度に戻せます。
  • atan2で得られた角度を元に、正弦と余弦を計算すれば、 原点から座標までの横の距離と縦の距離が導き出せます。 これを使えば、味方を直接狙う弾という実装が可能です。
  • 自分を中心として円形に弾を出すには「r = 360度/弾数」を基本角度として、for文等で回します。 例えば、Zという変数にrを加算しつつ正弦と余弦を計算すれば、 「全弾の角度」と「縦と横の移動距離」が導き出せます。

その他のメンバー

公式リファレンスでは数学関数の詳細が書かれていませんので、 その他のメンバー関数とメンバープロパティについて補足しておきます。 ※よく使われそうなものに留めます。

abs(x)xの絶対値を返します。絶対値とは、簡単に言えば符号を取り除いた数値です。Math.abs(-0.33)なら0.33を返します。
round(x)xを四捨五入した数を返す。Math.round(0.4)は0.0、Math.round(1.5)は2です。
max(num1,num2)
min(num1,num2)
maxは二数の大きいほう、minは小さい方を返します。 max(1,2)は2を、min(100,20)は20を返します。(もちろん、通常は値の判別が出来ない変数を引数にします。)
PI円周率を指します。円の面積を求める場合など、3.14を掛けるよりもPIを利用する方が精度が高くなります。
例) 2 * Math.PI * r (rは半径)