KAEDE Hack blog

JavaScript 中心に ライブラリなどの使い方を解説する技術ブログ。

JS ゲーム製作 -- box-intersect で四角形同士の衝突を検知したいが想像通りの挙動にならない

why

qiita.com

この記事を Twitter で見た。

衝突判定ライブラリなんてあるんだ、触ってみようかなって思った

box-intersect

github.com

box-intersect とは?

D 次元や N と M ボックスでそれぞれの交差を見つけるライブラリ。

O((n+m) log^d(n+m)) という式を使ってメモリの余分な割り当てを防ぐ

ベンチマークが高いらしい。重くなりにくいってことですね!

0fps.net

詳しい数式の話は全くわからない..

丸ごとのゲーム画面ライブラリではなくて、index.js とあるように、js のみ。

なので 実際に可視化されて見えたり、ものが動くロジックは別で書く必要がある。

四角形同士の重なりの検知を試してみる。

var boxIntersect = require('box-intersect')

//Boxes are listed as flattened 2*d length arrays
var boxes = [
  [1, 1, 2, 2],   //Interpretation: [minX, minY, maxX, maxY]
  [0, -1, 3, 2],
  [2, 1, 4, 5],
  [0.5, 3, 1, 10]
]

//Default behavior reports list of intersections
console.log('overlaps:', boxIntersect(boxes))

//Note:  Boxes are closed

//Can also use a visitor to report all crossings
var result = boxIntersect(boxes, function(i,j) {
  console.log('overlap:', boxes[i], boxes[j])

  //Can early out by returning any value
  if(i === 2 || j === 2) {
    return 2
  }
})

console.log('early out result:', result)

box をいくつか決めて、それの overlaps (重なり) を検知して

  1. 衝突が起こっている座標たち
  2. 衝突判定になっている四角形1
  3. 衝突判定になっている四角形2
  4. 衝突判定になっている四角形の総数

を出力するコードだと推測する。

実際に書いてみる

clone して使うわけではなく、npm i で使うようだ

適当なディレクトリを切って、npm install する

npm i box-intersect
added 4 packages, and audited 5 packages in 4s

found 0 vulnerabilities

さっきのコードをコピペして npm で実行

vi main.js
node main.js
overlaps: [ [ 1, 0 ], [ 1, 2 ], [ 0, 2 ] ]
overlap: [ 0, -1, 3, 2 ] [ 1, 1, 2, 2 ]
overlap: [ 0, -1, 3, 2 ] [ 2, 1, 4, 5 ]
early out result: 2

ちゃんと動いている!!!

自分の数値を入れて試す

0,0 to 1,1

0,0 to 2,2

0,0 to 3,3

この3つの box を作る。

これで 0,0 to 1,1 の地点でのみの交差で

3つの boxes とも overlap と出たら成功である

var boxes = [
  [0, 0, 1, 1],   //Interpretation: [minX, minY, maxX, maxY]
  [0, 0, 2, 2],   //Interpretation: [minX, minY, maxX, maxY]
  [0, 0, 3, 3],   //Interpretation: [minX, minY, maxX, maxY]
]

数値を入れて実行!

node main.js
overlaps: [ [ 2, 1 ], [ 2, 0 ], [ 1, 0 ] ]
overlap: [ 0, 0, 3, 3 ] [ 0, 0, 2, 2 ]
early out result: 2

結果は衝突箇所が 2,1 と 2,0 と 1,0

衝突した四角形が 0,0,3,3 と 0,0, 2,2

衝突した四角形の数が 2つ

になった。図示してみる

f:id:kei_s_lifehack:20210413044729p:plain

これで実際に交差判定になっているのは

1,0 と 2,0 と 2,1 のみ。

その後下に下がって 2,2 -> 1,2 -> 0.2 と行かないのが不明

赤 (0,0 to 2,2) と緑 (0,0 to 3,3) のみの衝突だとしても、なぜ右上三箇所だけなのか

青 (0,0 to 1,1) は どうして接触にならないのか

が全くわからない

シンプルに前例を二つにする

  [1, 1, 2, 2],   //Interpretation: [minX, minY, maxX, maxY]
  [0, -1, 3, 2],

これだけで衝突判定を出す、すると

overlaps: [ [ 1, 0 ] ]
overlap: [ 0, -1, 3, 2 ] [ 1, 1, 2, 2 ]
early out result: undefined

f:id:kei_s_lifehack:20210413050629p:plain

全然当たってない 1,0 のみが衝突になるし、当たっている図形は 0 なる、何もわからない

懸念

[minX, minY, maxX, maxY]

が 最初の xy から 次の xy に線を伸ばして 四角形を作っていると解釈しているが、 これがそもそも全然違うかもしれない

角しか当たらない疑惑

npm のこのライブラリのサイトをみていたら

Note The boxes are treated as cartesian products of closed intervals.

For example, the boxes [1,1,2,2] and [0,0,1,1] will be reported as intersecting by this module.

1,1 to 2,2 と 0,0 to 1,1 はこのライブラリでは交差してると扱われるよー

って注釈があった。

もしかして、角と角で当たってないと衝突にならないのでは?

f:id:kei_s_lifehack:20210413052309j:plain

こうやって既に入っているのは衝突では無いのでは?

角で当てて試してみる

overlaps: [ [ 0, 1 ] ]
overlap: [ 0, 0, 2, 2 ] [ 2, 2, 3, 3 ]
early out result: undefined

2,2 で交わって欲しいのに、擦りもしないところで交差してる....

overlaps: [ [ 0, 1 ] ]
overlap: [ 0, 0, 2, 2 ] [ 1, 1, 3, 3 ]
early out result: undefined

0,0 to 2,2 と 1,1 to 3,3 で当てても、接触位置と接触四角数はおかしいが、

接触している四角形のリストだけは想定通りに出ているのがわかった、これなら使えるかもしれない。

f:id:kei_s_lifehack:20210413044729p:plain

しかし最初に作ったこの四角形では青の一番小さい四角形が接触になっていない...

Canvas でシュミレーターでも作って試してみるか...