LOCKYOUで学ぶ

パラフドーム後日談

戻る

さて、前回は4分木空間分割について概念的な話をしたんだけど
今回は実際にプログラムを組んでみるよ
プログラムを組むって、何の言語で組むんだ?
今回もjavascriptのphina.jsでやるんだけど、
なるべく応用できるように解説するようにはするよ
さて、まず考えなきゃいけないのは
再帰的に4分割した部屋のどこにオブジェクトが入るの?っていうことなんだけど
あ、今回は3回分割するよ
ん?この番号の振り方ちょっと変わってるな
そこが今回のくそみそテクニックなんだよね
モートン序列(モートン順序)っていうんだけど、2進数使って表したら規則性がわかると思うよ
連番としてはこのようにZの形に番号が再帰的に割り振られることになります
一桁ずつで縦横を表してるのか
そーなんでちゅ
まああとそれぞれの階層とか部屋の番号とかを「2階層の部屋8」みたいに言うの面倒だから
「H2R8」とかっていうね
Hはhierarchy、RはRoomってことだな
それでだ、オブジェクトがどこに入るかをどうやって割り出すんだ
まずはオブジェクトの前に、
「点」がどこに入るかを割り出してみよう
「面」のオブジェクトはそのあとね
点はまあ必ず一番下の階層にあるってことになるんだけど
点がどこにあるかだろ?
横の場合は「X/一つの部屋の横の長さ」(小数点以下切り捨て)
縦の場合は「Y/一つの部屋の縦の長さ」(小数点以下切り捨て)
でそれぞれで「左上の部屋からそれぞれ何番目の部屋にあるか」がわかるが……
00 01 02 03 04 05 06 07
08 09 10 11 ...
って並んでくれていれば「Y*8+X」でわかるんだが
そこは後々で有利に働いてくれるんだけど若干めんどくさいところなんだね、仕方ないね
さっきも言ったように1桁ずつとびとびになってるから
ビット演算で噛み合うようにしないといけないんだよね
javascriptの数値はまあ
32ビット 正確にはjavascriptの数値は64bitの浮動小数点数ですが
ビット演算をやった場合のみ32bit整数として扱われるようです
bigIntについては性質上不定となるようです
って考えてもらえばいいからこんな感じで
左へビットをずらした奴と元のやつをOR→余計な部分を消すためにマスクをAND
って感じでやってくよ
n 0000 0000 0000 0000 abcd efgh ijkl mnop n << 8 0000 0000 abcd efgh ijkl mnop 0000 0000 (n or n << 8) 0000 0000 abcd efgh ???? ???? ijkl mnop 0x00ff00ff 0000 0000 1111 1111 0000 0000 1111 1111 (n or n << 8) and 0x00ff00ff 0000 0000 abcd efgh 0000 0000 ijkl mnop

function bitSeparate32(n) {
    n = (n|(n<<8)) & 0x00ff00ff;
    n = (n|(n<<4)) & 0x0f0f0f0f;
    n = (n|(n<<2)) & 0x33333333;
    return (n|(n<<1)) & 0x55555555;
}

			
bitSeparate32関数を使えば
bitSeparate32(X) | (bitSeparate32(Y)<<1)
でその点がどこの部屋に入っているかを割り出すことができるわけか
点が入る部屋の番号はこれで求め方がわかったな
点の所属空間がわかって喜んでいてはいけません!!!!
うるせーな
面のオブジェクトについてはどうすればいいんだ?
面については「左上」と「右下」の二つの点の所属部屋をまず調べるよ
この場合の「左上」っていうのはそのオブジェクトの一番上のy座標と一番左のx座標が交わった部分ね
上の説明だとわかりにくいかな?
ざっくり言えばそのオブジェクトを完全に覆える
長方形 この長方形の辺はX軸やY軸と平行です
軸平行境界ボックスっていうらしいです
の左上の位置だね
左上と右下って前回のアレにもかかれてたな
その長方形の左上の点と右下の点をさっきの方法で調べて、
その二つの点をどうすればオブジェクトの部屋の番号がわかるんだ?
ちょっと話がさかのぼるけど、
これ、さっきの部屋の画像ね
この
最下層 最下層に限らず、すべての階層の部屋の番号は
後述のように上の階層の部屋の番号を引き継ぎます
の部屋の番号って、
上の階層の部屋番号を引き継いでるんだよね
んー、どういうことだ?
まあこれは実際に見たほうがいいよね
例えばH3R38なんだけど、この38を2進数にすると100110になる
それでこの2進数を2ビットずつに分けるよ
とりあえず
デュエット 二重奏
8ビットを1オクテットというのに倣いました
って呼ぶけど、
この[10][01][10]を見るとこうなるね
先頭1デュエットはH1においての部屋の位置
先頭2デュエットはH2においての……ってなるわけか
それで二つの点を使ってオブジェクトの部屋番号を割り出す話に戻るんだけど
例えば38と39なら[10][01][10]と[10][01][11]で2デュエット目、つまり2階層目まで一致してる
ということは、階層はH2になるのか
で、H2のどこに入るのかで言えば、その一致してる場所[10][01]の9の部屋
つまりH2R9になるわけだな
ええぞ!ええぞ! あともう2個ぐらい例を出すね
38と44ならどうなる?
[10][01][10]と[10][11][00]で1デュエット目まで一致してるから
H1の[10]、つまりR2になるな
もう1個
38と56の場合は?
[10][01][10]と[11][10][00]
これは先頭も一致してないから……H0、R0ってことでいいのか
ナイスでーす!
とまあこんな感じでやっていけばオブジェクトの部屋の位置も割り出せるってわけ
そうか
それで次は……別のオブジェクトとの衝突予想リストか?
あ~っとその前に今回話した内容を実際にプログラムに組んでみたいんだよね
実装するって言いながら理論だけの話になっちゃったしね
それじゃまたね~