ブロックくずしを作る6「ブロック配置の仕様」

ブロック配置の仕様を決める

前回まででブロックを表示できるようなり、とりあえず横5個×縦3個を配置しました。

今回はブロックをゲームエリア内のどこにどれだけ配置するのかを決めましょう。

上の図は、ゲームエリアとブロックの配置の例を示したものになります。

赤い四角の枠線がゲームエリアです。水色の四角がブロック、緑色の四角がラケットです。

まずゲームエリアを上から1/3づつ、上段、中段、下段に分けます。2つの点線は1/3の境目を示しています。

ブロックは上段の内部になるべく多く配置することにします。ゲームエリアの左右の辺や上段と中段の境目からははみ出すことができません。

ブロックは他のブロックと一定の間隔を空けて並べることにします。最上段のブロックとゲームエリアの上限の間も同じ間隔を空けることにします。

また、左右に偏ることなく、中心線で対象になるように並べることにします。

数値を計算する

具体的な数値を計算していきましょう。

以降の説明では、長方形の座標を計算することがありますが、長方形の中心座標を(X, Y)とし、左上の頂点の座標を(Left,Top)としています。また、長方形の横幅と高さをWidth, Heightとします。

基本的な定義

まず、ブロックに関連する3つの数値を次のように定義します。

$$BH: ブロックの高さ(Brick.Height)$$

$$BW: ブロックの横幅(Brick.Width)$$

$$BG: ブロック間の間隔(Brick.Gap)$$

また、ゲームエリアの長方形をAreaと定義します。

BrickSetの定義

今、ブロックの横の数がn個、縦の数がm個だと仮定します。そして、n×m個のブロックを並べたときの全体の長方形をBrickSetと定義します。

BrickSetの横幅とn

n個のブロックが並び、その間に(n-1)個の隙間(Gap)があるので、BrickSetの横幅(Width)を計算する式は下のようになります。

\begin{split}
BrickSet.Width &= BW \times n + BG \times (n-1) \\
&=(BW + BG) \times n - BG
\end{split}

この値がゲームエリアからはみ出してはいけません。ゲームエリアの横幅はArea.Widthなので、

\begin{split}
BrickSet.Width &≦ Area.Width \\
(BW+BG) \times n - BG &≦Area.Width \\
(BW+BG) \times n &≦Area.Width + BG \\
n&≦\frac{Area.Width + BG}{BW+BG}
\end{split}

となります。この条件を満たす最大の整数nを計算するTypeScriptのコードは下に様になります。

n = Math.floor((Area.Width+BG) / (BW+BG)); 

BrickSetの高さとm

BrickSetの高さ(Height)を計算する式は下のようになります。

\begin{split}
BrickSet.Height &= BH \times m + BG \times (m-1) \\
&=(BH + BG) \times m - BG
\end{split}

この値がゲームエリアの1/3からはみ出してはいけません。また、最上段のブロックとゲームエリアの上限の間もBGの間隔を空ける仕様になっています。そのため、

\begin{split}
BrickSet.Height + BG &≦ \frac{Area.Height}{3} \\
(BH+BG) \times m &≦\frac{Area.Height}{3} \\
m&≦\frac{Area.Height}{3 \times (BH+BG)}
\end{split}

となります。この条件を満たす最大の整数mを計算するTypeScriptのコードは下に様になります。

m = Math.floor(Area.Height / (BH+BG) / 3); 

最低条件を追加する

ゲームエリアの最小サイズ

ゲームエリアが小さいと、並べることのできるブロックの数も減ってしまいます。もしゲームエリアの横幅や高さがブロックのそれより小さければ、並べることのできるブロックの数は0になってしまいます。それではゲームになりません。

そこで、並べることのできるブロックの最小条件を下の様に決め、これを仕様に追加します。

  1. 横方向には最低でもMinColumn個のブロックを配置する。
  2. 縦方向には最低でもMinRow個を配置する。

これを最小条件とします。つまり前述の計算で導き出したmとnは、\(n≧MinColumn, m≧MinRow\)でなければなりません。

これによりArea.WidthとArea.Heightの最小値が決まります。

\begin{split}
\frac{Area.Width + BG}{BW+BG} &≧n\\
\frac{Area.Width + BG}{BW+BG} &≧MinColumn\\
Area.Width + BG &≧MinColumn \times (BW+BG)\\
Area.Width &≧MinColumn \times (BW+BG) - BG
\end{split}

\begin{split}
\frac{Area.Height}{3 \times (BH+BG)} &≧MinRow\\
\frac{Area.Height}{3 \times (BH+BG)} &≧MinRow\\
Area.Height &≧3 \times MinRow \times (BH+BG)
\end{split}

キャンバスの最小サイズ

ゲームエリアの最小サイズが決まったなら、キャンバスの最小サイズも決めることができます。ゲームリアとキャンバスとのサイズの関係仕様は、以下で記載しています。

キャンバスの長方形をCanvasと定義するなら、

\begin{split}
Canvas.Width-40&=Area.Width \\
Canvas.Height-60&=Area.Height
\end{split}

なので、

\begin{split}
Canvas.Width &= Area.Width + 40 \\
&≧MinColumn \times (BW+BG) - BG + 40 \\
Canvas.Height &= Area.Height + 60 \\
&≧3 \times MinRow \times (BH+BG) + 60
\end{split}

となります。

ブロックの座標

BrickSetの座標

ブロックの座標について計算しましょう。個々のブロックの座標を計算する前にまずは、BrickSetの座標を考えます。

まず、この長方形の横幅と高さは、すでに説明したBrickSet.WidthとBrickSet.Heightです。

また、この長方形の中心座標のX軸はゲームエリアの中心座標と一致します。なぜならば、ブロックを並べるとき、全体は左右に偏ることなく、ゲームエリアの中心線で対象になるように並べるという仕様だからです。つまり、
$$BrickSet.X = Area.X$$
です。BrickSetの左辺のX座標は、
$$BrickSet.Left = BrickSet.X - \frac{BrickSet.Width}{2}$$
となります。
また、最上段のブロックとゲームエリアの上限の間はBGの間隔を空ける仕様になっているので、
$$BrickSet.Top = Area.Top + BG$$
です。

そうすると、BrickSetの中心座標のY軸は、
\begin{split}
BrickSet.Y &= BrickSet.Top + \frac{BrickSet.Height}{2} \\
&=Area.Top + BG+ \frac{BrickSet.Height}{2}
\end{split}
となります。

最も左上のブロックの座標

全てのブロックの中でもっとも左上にあるブロックについて考えます。このブロックの長方形をBrick0とします。

Brick0の左上の座標はBrickSetの左上の座標と一致します。そのため、
\begin{split}
Brick0.Left &= BrickSet.Left\\
Brick0.Top &= BrickSet.Top\\
\end{split}
となります。

ブロック横幅と高さはBWとBHなので、左上の座標からbrick0の中心座標を算出できます。
\begin{split}
Brick0.X &= Brick0.Left + \frac{BW}{2}\\
&=BrickSet.Left+ \frac{BW}{2}\\
Brick0.Y &= Brick0.Top + \frac{BH}{2} \\
&=BrickSet.Top +\frac{BH}{2}
\end{split}

他のブロックの座標

他のブロックはBrick0を基準にして計算することができます。つまり、Brick0を基準として右にi番目、下にj番目のブロックBrick(i,j)の座標は、
\begin{split}
Brick(i,j).X &= Brick0.X + (BW+BG) * i \\
Brick(i,j).Y &= Brick0.Y + (BH+BG) * j
\end{split}
となります。

コメント