Minecraft Programming

Abstract#

マイクラ上で球を描いてみたときに面白かったのでその記録を。

Topic#

まず円を描く#

自分中心に半径rブロックの円を考えます。下図のように円周上に等間隔の点の座標を求めていくのですが、隣のブロックとの間に隙間を作らないためには、点と点の間が、x方向にもz方向にも1以上離れないようにする必要があります。
θが0の時の点をP0としたとき、例えばz方向に一番大きく移動するのは、θが0付近つまり、P0からP1に行く時です。そうすると下図のように近似的に考えることができます。
Δθの最大値は、asin(1/r)になりますね。そして、2πをΔθの最大値で割れば、1周360度するのに必要な点の数Nがわかります。N=2π/Δθですね。
n番目の点をPnとすると、Pnの座標(xn, yn)は(r*cos(n*Δθ), r*sin(n*Δθ))で表せます。その時nは0からNを取ります。
なので、高さ方向の変数hを使うと、円を描く関数は下記のようになるのです。 
function circle(r: number, h: number){
    dt = Math.asin(1/r);
    N = 2 * PI / dt;
    for(let i = 0;i < N;i++){
        block.place(SEA_LANTAN, pos(r * Math.cos(i * dt), h, r * Math.sin(i * dt)));
    }
}

球を描くには#

下図のように水平方向に円を描き、縦方向に重ねていくとできます。この円の半径と高さ方向の数字がわかれば、上記の関数circle(r,h)が使えるわけです。
z=0平面で切ると下記のようになるのですが、仰角βを等間隔に取っていこうとすると円の時と同じように隙間ができないように考えると下記が成り立ちます。なおベータは、真下が―90度、真上が+90度と考えます。
Δβの最大値は、asin(1/r)になります。そして、πをΔβの最大値で割れば、真下から真上まで180度仰角が変化するのに必要な点の数Mがわかります。M=π/Δβですね。
m番目の点をQmとして、上図のように考えると、mは-M/2から+M/2の範囲を取ります。Qmの半径は、r*cos(m*Δβ)となり、その時の高さ方向の数字、つまりその時のy座標は、r*sin(m*Δβ)となります。
なので、球を描こうとすると下記を実行すればよいわけです。
db = Math.asin(1/r);
M = PI/db;
for(let j = -M/2; j<M/2; j++){
    circle(r*cos(j*db), r*sin(j*db));
}
実際のコードはこんな感じ。変数を統合したりしてます。楕円体書くときまた分離するのかな。

Reference#