見出し画像

JavaScriptのそれ、いつ使うの?〜Math.xxx編〜

こんにちは!#web開発塾一期生のじょこじょこです!

今日は開発塾で作成中のゲームの中で使ったMathオブジェクトについて、復習も兼ねて書いていこうと思います!

Mathオブジェクトといえば、よく使われるのはMath.randomではないでしょうか?私は今までこのMath.randomとMath.floorくらいしか使ったことありませんでした。

しかしMathさんには他にも色々なプロパティ、静的メソッドがあります…というのは知ってましたが、正直「それ、いつ使うん?」と常々思っておりました。しかしゲームを作っていて、なるほどね〜!!と感動したのであります!それを伝えたいだけです!それでは、いってみよー!(長文です)

Math.abs()

私はVBAに触れたことがないので今回初めて知りましたが、普段エクセルやスプレッドシートを使いこなしてる方には馴染みがあるかもしれません。

簡単に説明すると

Math.abs() 関数は、数値の絶対値を返します。(MDN公式ドキュメントより)

だそうです。ほーーん。絶対値ってなんですか?

ということで調べました。0からどれくらい離れているか距離を表す値だそうです。what?図を用意しました。

スクリーンショット 2021-04-07 21.23.03

どっちの方向に行こうが、0からの距離は10ですね。この場合、距離を表す値=絶対値=10となります。なので以下のように

//絶対値を返す関数を用意
function difference(a, b) {
 return Math.abs(a - b);
}

console.log(difference(2, 6)) // 4

とあった場合、2-6=-4 → 0からの距離は4 となり、コンソールには4と出力されます。

で、それをいつ使うんですか?って話ですね。
例えばゲームでは、何かと何かがぶつかったら何かが起こるみたいな設定はよくあると思います。敵にぶつかって倒れる、飛行機からミサイルを発射してぶつける などなど。下図のような状態を当たり(接触)とみなします。

スクリーンショット 2021-04-07 21.47.09

さあ、これをif文を使って判定式を書きましょう!…となると、ちょっと面倒だしややこしいし、よくわかりませんよね。
では、青とオレンジのx,yそれぞれの中心値を取って、2つの距離がある程度近づけばOKということにしてみます。
どういうことでしょうか?仮に中心値をcenterX,centerYとすると、次のように表せます。

スクリーンショット 2021-04-09 21.51.30

これをコードで表すとこんな感じです。オブジェクト指向で書いています。

// 青とオレンジに共通するクラス
class Rect {
 constructor(x, y, width, height) {
   this.x = x;
   this.y = y;
   this.centerX = null;
   this.centerY = null;
   this.width = width;
   this.height = height;
 }
 // オブジェクトの真ん中
 calculateCenterPos() {
   this.centerX = this.x + this.width / 2;
   this.centerY = this.y + this.height / 2;
 }
}

そして以下のcomputedDistance関数内で青とオレンジの中心からの差が出せます。

// 青とオレンジに共通するクラス
class Rect {
 //constructorなど省略
 
 // 対象との衝突差
 // 引数objにインスタンス化したオレンジか青の変数を入れる(のちほどコード出てきます)
 computedDistance(obj){
   const distX = obj.centerX - this.centerX
   const distY = obj.centerY - this.centerY
 }
}

しかしこの式だと、オレンジと青の位置が逆転した場合、値はマイナスになります。そこでようやくMath.absの出番です

// 対象との衝突差
// 引数objにインスタンス化したオレンジか青の変数を入れる(のちほどコード出てきます)
 computedDistance(obj){
   const distX = Math.abs(obj.centerX - this.centerX)
   const distY = Math.abs(obj.centerY - this.centerY)
   
   // それぞれの中心の差が100以下だったら当たったことにする
   return distX <= 100 && distY <= 100
 }

こうすれば、位置が逆転しても距離がマイナスになることはありません!
あとはif文を使って青オレンジどちらかのオブジェクトでcomputedDistanceの戻り値がtrueだったら何かが起こる設定にしてあげれば良さそうです。
全部完成したバージョンがこちらです(canvasの設定は省略します)

// 青とオレンジの共通項目
class Rect {
 constructor(x, y, width, height) {
   this.x = x
   this.y = y
   this.centerX = null
   this.centerY = null
   this.width = width
   this.height = height
 }
 // 対象との衝突差
 computedDistance(obj){
   const distX = Math.abs(obj.centerX - this.centerX)
   const distY = Math.abs(obj.centerY - this.centerY)
   return distX <= 100 && distY <= 100
 }
 // オブジェクトの真ん中
 calculateCenterPos() {
   this.centerX = this.x + this.width / 2
   this.centerY = this.y + this.height / 2
 }
 draw(color) {
   ctx.fillStyle = color
   ctx.fillRect(this.x, this.y, this.width, this.height)
 }
}

// 青い四角クラス
class Blue extends Rect {
 constructor(x, y, width, height) {
   super(x, y, width, height,)
   this.speed = 20 // キーイベントで進む距離
 }
 update() {
   ctx.clearRect(0, 0, canvasW, canvasH)
   this.draw('#006ede') // 青
   this.calculateCenterPos()
   // ここで接触判定
   if(this.computedDistance(orange)){
     console.log('オレンジにぶつかってます!!')
   }
 }
 moveRight() { this.x += this.speed }
 moveLeft() { this.x -= this.speed }
 moveDown() { this.y += this.speed }
 moveUp() { this.y -= this.speed }
}

// オレンジ四角クラス
class Orange extends Rect {
 constructor(x, y, width, height) {
   super(x, y, width, height,)
 }
 update() {
   this.draw('#ff8f00') // オレンジ
   this.calculateCenterPos()
 }
}

let blue = new Blue(240, 240, 100, 100)
let orange = new Orange(400, 150, 100, 100)

window.onkeydown = (event) => {
 if (event.code === 'ArrowUp') {
   blue.moveUp()
 } else if (event.code === 'ArrowRight') {
   blue.moveRight()
 } else if (event.code === 'ArrowLeft') {
   blue.moveLeft()
 } else if (event.code === 'ArrowDown') {
   blue.moveDown()
 }
 blue.update()
 orange.update()
}

こんな感じにしてあげれば下の動画のようになります!

画像5

近づくと距離(distX,distY)が小さくなってるのがわかります。

以上!Math.absの話でした!続きまして(まだあるんかい!!)今のをもう少し数学っぽくリファクタしてみたいと思います。


Math.pow()&Math.sqrt()

答えを先に言ってしまうと、Math.pow()は第一引数を第二引数乗したものだそうです。なんのこっちゃ。下記の通りです。

// 8の3乗 8*8*8
Math.pow(8,3)   // 512

// -7の3乗 -7*-7*-7
Math.pow(-7, 3)   // -343

そしてMath.sqrt()は平方根を返します。ほーーん。平方根って何ですか?
またしても調べました。

平方根とは、「2乗する前の数 」4の平方根は2と-2だ!
by トライさん

はあ…そうですか。powで累乗してsqrtで2乗する前に戻す?この2つで何がしたいんですかね。と思いますよね。しかしこのpowさんとsqrtさんを組み合わせると三平方の定理をもとに2点間の距離が求められるのです!!

意味が、わから、ない!!三平方の定理?2点間の距離?ってなんじゃい!!これだよ!ドン!

スクリーンショット 2021-04-10 16.01.50

先ほど青とオレンジのx,yの差を出しましたね。これです。

// 対象との衝突差
 computedDistance(obj){
   const distX = Math.abs(obj.centerX - this.centerX)
   const distY = Math.abs(obj.centerY - this.centerY)
   return distX <= 100 && distY <= 100
 }

最後のreturnのところで三平方の定理を使ってみるとこんな感じ!

// 対象との衝突差
 computedDistance(obj) {
   const distX = Math.abs(obj.centerX - this.centerX)
   const distY = Math.abs(obj.centerY - this.centerY)
   // 三平方の定理
   let dist = Math.sqrt(Math.pow(distX, 2) + Math.pow(distY, 2))
   return dist <= 100
 }

スクリーンショット 2021-04-09 23.37.24

こうすることで2点間の中心を出してx,yそれぞれで判定していたのを、2点間の距離で判定できるわけです。

というわけで長くなりましたけど、Mathオブジェクトの一部を紹介しました。コードの書き方というより考え方の話だったのでコードの全部の解説を書きませんでしたが、なんか距離を出したい時にMath.sqrtとか使うんだっけ〜?と思い出していただければと思います。

最後に

今日ご紹介したMath.abs、Math.sqrtを使用して作成中のゲームです。

画像7

#web開発塾ではゲーム開発を通じてプログラミングの基礎〜応用が学べます🎮
初学者がアプリ作成からスタートすると、画面作成だけで疲れてしまうと思います。(私がそうでした)
ゲーム開発は初めからいくつも画面を作ることもないし、複雑なログインやCRUD処理も必要ありません。徐々にステップアップできるので、やっていて楽しいし挫折しにくいですよ!

興味ある方は#web開発塾をチェックしてみてください😊

それでは!

この記事が気に入ったらサポートをしてみませんか?