DXRuby：「当たり判定」を自分で作ってみよう　B. 円の中心からの距離で判定する

# 概要
この記事は中学高校生向けプログラミング教室の教材として作ったものを一部改変したものです。


今回の記事は、
・[DXRuby：「当たり判定」を自分で作ってみよう - Qiita](https://qiita.com/noanoa07/items/b7d647bba20116c41a77)

● 当たり（衝突）判定の方法
[A. 四角形の四隅の座標で判定する](https://qiita.com/noanoa07/items/0d62604c769b9810c905)
B. 円の中心からの距離で判定する
[C. 色で判定する](https://qiita.com/noanoa07/items/52eda04c7150dd3c1ea8)

の内の
`B. 円の中心からの距離で判定する`
になります。

<img width="50%" alt="atari_en7b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/5499c4f7-f956-7ddb-946e-1bd6d6ec98c5.png">

<img width="50%" alt="atari_en8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/1be86059-960c-e56a-b399-9493ba0f536d.png">

前の記事
・[DXRuby：「当たり判定」を自分で作ってみよう　A. 四角形の四隅の座標で判定する - Qiita](https://qiita.com/noanoa07/items/0d62604c769b9810c905)

次の記事
・[DXRuby：「当たり判定」を自分で作ってみよう　C. 色で判定する](https://qiita.com/noanoa07/items/52eda04c7150dd3c1ea8)



# 技術解説
- 使用ライブラリ
- 参考サイト
については、上記記事を参照してください。

## ソースコード
https://github.com/noanoa07/dxruby_blocks


## ライセンス
ソースコード、本解説ともにパブリックドメイン



# プログラム解説
## B. 円の中心からの距離で判定する
→ 「ブロック崩し」追加課題 1b)；衝突判定の自作（円） - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2046462.html

### B-1a. `===`を使った準備：判定相手が単独（atari_en0.rb）
DXRubyのスプライトでは、`===`を使うと、衝突の有/無で`true`/`fasle`を返します。

`ball`（小さい円）が、`block`（大きい円）と衝突しているかを`===`で判定します。
衝突/非衝突 の結果をターミナル（コマンドプロンプト）に`true`/`false`で出力しつつ、`block`の色も`赤`/`白`にします。
また、ウィンドウに衝突時は`hit!`の文字列を表示します。

`===`はデフォルトでは四角形で衝突を判定するので、 このままでは円同士が接触する前に`衝突`と判定されています。

```atari_en0.rb
require 'dxruby'

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball  = Sprite.new(300, 400, image0)
block = Sprite.new(200, 130, image1)

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  result = (ball === block)
  p result

  if result
    Window.draw_font(0, 0, "hit!", font)
    block.image = image2
  else
    block.image = image1
  end

  block.draw
end
```

<img width="50%" alt="atari_en0a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d2597f8f-c703-84a8-882a-d066f738a565.png">

<img width="50%" alt="atari_en0b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/714a0ccf-9427-417d-70d7-f763f62c8e6d.png">

<img width="50%" alt="atari_en0c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/b337330c-46bc-1142-a0d6-b047d85bb6c2.png">


### B-1b. `===`を使った準備：衝突判定範囲を円に設定（atari_en1.rb）
`スプライト.collision = [配列]`で衝突範囲の設定ができます。配列に3つの要素を指定すると円で判定するようになります。

`スプライト.collision = [x, y, r]`；中心(x, y)、半径rの円

これで、円同士がぎりぎり接した時に`衝突`と判定されるようになります。

→ DXRubyリファレンス：API INDEX；Sprite#collision=

http://mirichi.github.io/dxruby-doc/api/Sprite_23collision_3D.html

```atari_en1.rb
require 'dxruby'

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball  = Sprite.new(300, 400, image0)
block = Sprite.new(200, 130, image1)

ball.collision  = [ 50,  50,  50]
block.collision = [100, 100, 100]

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  result = (ball === block)
  p result

  if result
    Window.draw_font(0, 0, "hit!", font)
    block.image = image2
  else
    block.image = image1
  end

  block.draw
end
```

<img width="50%" alt="atari_en1a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/3a55c672-f95a-93a4-b6c3-d1c929168a6a.png">

<img width="50%" alt="atari_en1b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/3133fda0-6601-a866-981c-d0d7b032f2be.png">

<img width="50%" alt="atari_en1c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/bf1314b4-f859-281b-8f40-ed6bd74670d0.png">


### B-1c. `atari?`を自作：判定相手が単独（atari_en2.rb）
`atari?(jibun, aite)`を作って、 衝突の有/無で`true`/`fasle`を返すようにします。

判定方法は、互いの円の中心からの距離を比較します。

1. それぞれを円と考えて半径を決める（長方形の長辺と短辺の平均を半径とする）
2. 互いの半径を足した長さを求める
3. それぞれの中心の座標を求める
4. 互いの中心からの距離を求める
5. `中心から中心の距離`と`半径の和`を比較する

```ruby
# radius；半径
# center；中心
rad_x0 = jibun.image.width / 2   # jibunの横幅の 1/2
rad_y0 = jibun.image.height / 2  # jibunの縦幅の 1/2

(rad_x0 + rad_y0) / 2   # jibunの半径（長辺と短辺の平均で考える）

x0     = jibun.x        # jibunの左上隅のx座標
y0     = jibun.y        # jibunの左上隅のy座標

cen_x0 = x0 + rad_x0    # jibunの中心のx座標
cen_y0 = y0 + rad_y0    # jibunの中心のy座標
```
`中心から中心の距離`の求め方は、直角三角形のピタゴラスの定理を使います。

`距離**2 = 中心間のx座標の差**2 + 中心間のy座標の差**2`

（Rubyでは、`**2` は 2`乗`の意味）

実際は`距離の2乗`同志で比較していますが、これは平方根`sqrt`より2乗`**2`の計算の方が高速なためです。

それでは、自作した`atari?`を使って、`===`を使ったコードを書き換えてみます。

```atari_en2.rb
require 'dxruby'

def atari?(jibun, aite)
  x0     = jibun.x
  rad_x0 = jibun.image.width / 2
  cen_x0 = x0 + rad_x0

  y0     = jibun.y
  rad_y0 = jibun.image.height / 2
  cen_y0 = y0 + rad_y0

  x1     = aite.x
  rad_x1 = aite.image.width / 2
  cen_x1 = x1 + rad_x1

  y1     = aite.y
  rad_y1 = aite.image.height / 2
  cen_y1 = y1 + rad_y1

  # 半径は長径と短径の1/2に設定
  # 半径同士の和
  cir_dis = (rad_x0 + rad_y0) / 2 + (rad_x1 + rad_y1) / 2

  # 2乗で比較する
  cir_dis_2 = cir_dis **2
  dist_2 = (cen_x0 - cen_x1) ** 2 + (cen_y0 - cen_y1) ** 2
  cir_dis_2 >= dist_2
end

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball  = Sprite.new(300, 400, image0)
block = Sprite.new(200, 200, image1)

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  result = atari?(ball, block)
  p result

  if result
    Window.draw_font(0, 0, "hit!", font)
    block.image = image2
  else
    block.image = image1
  end

  block.draw
end
```

<img width="50%" alt="atari_en2a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e66a68ba-cc7f-9227-6c59-eed6e48c9d90.png">

<img width="50%" alt="atari_en2b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e5352dde-a743-1a90-3705-1137d6ad065b.png">

<img width="50%" alt="atari_en2c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d4d8f98a-33f7-61e6-b26c-14c51a216018.png">


### B-2a. `===`を使った準備:判定相手が配列（atari_en3.rb）
DXRubyのスプライトでは、`===`は、相手がスプライトの配列でも、衝突の有/無で`true`/`fasle`を返します。

`ball`が、スプライトの配列`blocks`と衝突しているかを`===`で判定します。
`blocks`のいずれかと衝突していたら、ターミナル（コマンドプロンプト）に`true`で出力し、それ以外は`false`を出力します。
また、ウィンドウに衝突時は`hit!`の文字列を表示します。

```atari_en3.rb
require 'dxruby'

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball   = Sprite.new(300, 400, image0)

block1 = Sprite.new(110, 130, image1)
block2 = Sprite.new(390, 130, image1)

ball.collision  = [ 50,  50,  50]
block1.collision = [100, 100, 100]
block2.collision = [100, 100, 100]

blocks = [block1, block2]

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  result = (ball === blocks)
  p result

  if result
    Window.draw_font(0, 0, "hit!", font)
  end

  Sprite.draw(blocks)
end
```

<img width="50%" alt="atari_en3a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/11f22c09-843d-9474-9471-c3b568693f52.png">

<img width="50%" alt="atari_en3b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/bd5cb45c-dd8c-4e8d-9846-44b08db94f11.png">

<img width="50%" alt="atari_en3c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d197dabf-07ec-c705-50e2-18a6814e5026.png">

<img width="50%" alt="atari_en3d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d2e577f9-e5b0-bd25-2470-5b0aa8e096ee.png">


### B-2b. `atari_array?`を自作:判定相手が配列（atari_en4.rb）
`===`の代わりに、`atari_array?(jibun, array)`を自作します。
判定相手の配列の要素を一つずつ`atari?`で判定していきます。

自作した`atari_array?`を使って、コードを書き換えます。

```atari_en4.rb
require 'dxruby'

def atari?(jibun, aite)
  x0     = jibun.x
  rad_x0 = jibun.image.width / 2
  cen_x0 = x0 + rad_x0

  y0     = jibun.y
  rad_y0 = jibun.image.height / 2
  cen_y0 = y0 + rad_y0

  x1     = aite.x
  rad_x1 = aite.image.width / 2
  cen_x1 = x1 + rad_x1

  y1     = aite.y
  rad_y1 = aite.image.height / 2
  cen_y1 = y1 + rad_y1

  # 半径は長径と短径の1/2に設定
  # 半径同士の和
  cir_dis = (rad_x0 + rad_y0) / 2 + (rad_x1 + rad_y1) / 2

  # 2乗で比較する
  cir_dis_2 = cir_dis **2
  dist_2 = (cen_x0 - cen_x1) ** 2 + (cen_y0 - cen_y1) ** 2
  cir_dis_2 >= dist_2
end

def atari_array?(jibun, array)
  array.each do |a|
    if atari?(jibun, a)
      return true
    end
  end
  false
end

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball   = Sprite.new(300, 400, image0)

block1 = Sprite.new(110, 130, image1)
block2 = Sprite.new(390, 130, image1)

blocks = [block1, block2]

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  result = atari_array?(ball, blocks)
  p result

  if result
    Window.draw_font(0, 0, "hit!", font)
  end

  Sprite.draw(blocks)
end
```

<img width="50%" alt="atari_en4a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/fb6e5d86-a70b-ac8a-fa9b-20d222ea379b.png">

<img width="50%" alt="atari_en4b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/31a9f8d9-4f4d-c0ca-53c5-1b55ddafdbba.png">

<img width="50%" alt="atari_en4c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/6edc455b-4874-b4ca-e6c8-a0c249572df9.png">

<img width="50%" alt="atari_en4d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/3d62e5f0-8b8c-07f8-2c28-b3559a5fc661.png">


### B-3a. `check`を使った準備（atari_en5.rb）
DXRubyの`===`や、自作した`atari_array?`では、どの相手に衝突したかは分かりませんでした。

一方、DXRubyのスプライトでは`check`を使うと、衝突している相手すべてを配列に入れて返します。（衝突していない時は、何も入ってない配列を返す）

この配列を`array`とすると、0番目の`array.first`（`array[0]`でも同じ）が最初に衝突した相手です。また、`array.first`に何か入っていれば衝突している、`空（nil）`ならば衝突していないという、当たり判定にも使えます。

→ DXRubyリファレンス：Spriteを使うためのチュートリアル；衝突したオブジェクトを取得する
http://mirichi.github.io/dxruby-doc/tutorial/sprite.html

→ DXRubyリファレンス：API INDEX；Sprite；check
http://mirichi.github.io/dxruby-doc/api/Sprite_23check.html

プログラムでは、`ball`が`blocks`のどれに最初に衝突しているかを `check.first`で判定します。
最初に衝突しているブロックをターミナル（コマンドプロンプト）に出力し、そのブロックを赤色にします。それ以外は`nil`を出力します。
また、ウィンドウに衝突時は`hit!`の文字列を表示します。

```atari_en5.rb
require 'dxruby'

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball   = Sprite.new(300, 400, image0)

block1 = Sprite.new(110, 130, image1)
block2 = Sprite.new(390, 130, image1)

ball.collision  = [ 50,  50,  50]
block1.collision = [100, 100, 100]
block2.collision = [100, 100, 100]

blocks = [block1, block2]

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  col = ball.check(blocks).first
  p col

  if col
    Window.draw_font(0, 0, "hit!", font)
    col.image = image2
    Sprite.draw(blocks)
    col.image = image1
  else
    Sprite.draw(blocks)
  end
end
```

<img width="50%" alt="atari_en5a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/8f550cae-de8b-5293-f3c8-037dc2a7f651.png">

<img width="50%" alt="atari_en5b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/0f16f81c-08a3-bdf3-26ef-2d05dfb9cc49.png">

<img width="50%" alt="atari_en5c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/b260bc05-df0c-f0b7-a2a8-ff5f9873df0e.png">

<img width="50%" alt="atari_en5d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/1cb5844c-9b11-762b-b5a4-9f13e073628e.png">


### B-3b. `atari_array`を自作（atari_en6.rb）
ぶつかった相手は最初のものだけ分かればよいので、DXRubyの`check.first`相当の`atari_array`を自作します。

つまり、`atari_array`は、衝突していないと`nil`を返し、衝突すると "`ぶつかった最初のもの`" を返します。

方法は、判定相手の配列の要素を一つずつ`atari?`で判定していき、最初に衝突している要素を返します。

自作した`atari_array`を使って、コードを書き換えます。

```atari_en6.rb
require 'dxruby'

def atari?(jibun, aite)
  x0     = jibun.x
  rad_x0 = jibun.image.width / 2
  cen_x0 = x0 + rad_x0

  y0     = jibun.y
  rad_y0 = jibun.image.height / 2
  cen_y0 = y0 + rad_y0

  x1     = aite.x
  rad_x1 = aite.image.width / 2
  cen_x1 = x1 + rad_x1

  y1     = aite.y
  rad_y1 = aite.image.height / 2
  cen_y1 = y1 + rad_y1

  # 半径は長径と短径の1/2に設定
  # 半径同士の和
  cir_dis = (rad_x0 + rad_y0) / 2 + (rad_x1 + rad_y1) / 2

  # 2乗で比較する
  cir_dis_2 = cir_dis **2
  dist_2 = (cen_x0 - cen_x1) ** 2 + (cen_y0 - cen_y1) ** 2
  cir_dis_2 >= dist_2
end

def atari_array(jibun, array)
  array.each do |a|
    if atari?(jibun, a)
      return a
    end
  end
  nil
end

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball   = Sprite.new(300, 400, image0)

block1 = Sprite.new(110, 130, image1)
block2 = Sprite.new(390, 130, image1)

blocks = [block1, block2]

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  col = atari_array(ball, blocks)
  p col

  if col
    Window.draw_font(0, 0, "hit!", font)
    col.image = image2
    Sprite.draw(blocks)
    col.image = image1
  else
    Sprite.draw(blocks)
  end
end
```

<img width="50%" alt="atari_en6a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/82556d14-420f-e40a-78b8-32d26cdb1fd4.png">

<img width="50%" alt="atari_en6b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/046490df-44d8-2f50-b1b2-2707b3562300.png">

<img width="50%" alt="atari_en6c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/5374d6a5-7a34-1c37-39c1-8eb11345aa2c.png">

<img width="50%" alt="atari_en6d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/b9900900-417c-eb31-230f-c1f7761ce155.png">


### B-4. 自作の当たり判定（円）を`Spriteクラスのメソッド`にする（atari_en7.rb）
元の`===`と`check`は、`Sprite`クラスのメソッド（命令）なので、書き方としては、`ball.check(blocks)`のようになります。

自作の`atari_array`も同じような書き方になるように、`Sprite`クラスのメソッドにしてみます。

`クラス`や`メソッド`についての説明はここでは説明を省きますので、詳しくはRubyのテキストを見てください。

クラスメソッドを追加する方法は簡単で、以下のようにします。

```ruby
class Sprite
  def 追加したいメソッド
    #追加したいメソッドの内容
  end
end
```


`Sprite`クラスに`atari?`と`atari_array`追加します。

ちなみに、`jibun`（自分）に相当するものは、`self`と書きます。

```ruby
class Sprite
  def atari?(aite)
    x0     = self.x
    rad_x0 = self.image.width / 2
    cen_x0 = x0 + rad_x0

    y0     = self.y
    rad_y0 = self.image.height / 2
    cen_y0 = y0 + rad_y0

    x1     = aite.x
    rad_x1 = aite.image.width / 2
    cen_x1 = x1 + rad_x1

    y1     = aite.y
    rad_y1 = aite.image.height / 2
    cen_y1 = y1 + rad_y1

    # 半径は長径と短径の1/2に設定
    # 半径同士の和
    cir_dis = (rad_x0 + rad_y0) / 2 + (rad_x1 + rad_y1) / 2

    # 2乗で比較する
    cir_dis_2 = cir_dis **2
    dist_2 = (cen_x0 - cen_x1) ** 2 + (cen_y0 - cen_y1) ** 2
    cir_dis_2 >= dist_2
  end

  def atari_array(array)
    array.each do |a|
      if self.atari?(a)
        return a
      end
    end
    nil
  end
end
```

これで、クラスメソッドになったので、今までの`atari_array(ball, blocks)`という書き方ではなく、`ball.atari_array(blocks)`というように書くことができるようになりました。

```atari_en7.rb
require 'dxruby'

class Sprite
  def atari?(aite)
    x0     = self.x
    rad_x0 = self.image.width / 2
    cen_x0 = x0 + rad_x0

    y0     = self.y
    rad_y0 = self.image.height / 2
    cen_y0 = y0 + rad_y0

    x1     = aite.x
    rad_x1 = aite.image.width / 2
    cen_x1 = x1 + rad_x1

    y1     = aite.y
    rad_y1 = aite.image.height / 2
    cen_y1 = y1 + rad_y1

    # 半径は長径と短径の1/2に設定
    # 半径同士の和
    cir_dis = (rad_x0 + rad_y0) / 2 + (rad_x1 + rad_y1) / 2

    # 2乗で比較する
    cir_dis_2 = cir_dis **2
    dist_2 = (cen_x0 - cen_x1) ** 2 + (cen_y0 - cen_y1) ** 2
    cir_dis_2 >= dist_2
  end

  def atari_array(array)
    array.each do |a|
      if self.atari?(a)
        return a
      end
    end
    nil
  end
end

image0 = Image.new(100, 100).circle_fill( 50,  50,  50, C_WHITE)
image1 = Image.new(200, 200).circle_fill(100, 100, 100, C_WHITE)
image2 = Image.new(200, 200).circle_fill(100, 100, 100, C_RED)

ball   = Sprite.new(300, 400, image0)

block1 = Sprite.new(110, 130, image1)
block2 = Sprite.new(390, 130, image1)

blocks = [block1, block2]

font = Font.new(32)

Window.loop do
  ball.x = Input.mouse_pos_x
  ball.y = Input.mouse_pos_y

  ball.draw

  col = ball.atari_array(blocks)
  p col

  if col
    Window.draw_font(0, 0, "hit!", font)
    col.image = image2
    Sprite.draw(blocks)
    col.image = image1
  else
    Sprite.draw(blocks)
  end
end
```

<img width="50%" alt="atari_en7a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/493437eb-2f0c-c455-91c3-651f85f90566.png">

<img width="50%" alt="atari_en7b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/5499c4f7-f956-7ddb-946e-1bd6d6ec98c5.png">

<img width="50%" alt="atari_en7c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/78f1649f-e1cd-112d-a103-3174b96293bf.png">

<img width="50%" alt="atari_en7d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c1cf13cd-5cb7-1b1a-99bc-396b89c6c6df.png">


### B-5. 自作の当たり判定（円）を使ったブロック崩し（atari_en8.rb）
「ブロック崩し」のプログラム`block28.rb`のブロックを`円`に変えたものを、自作の`atari_array`に書き換えてみましょう。

円にした`ブロック`と`ボール`の判定だけですが、元の`check.first`を同じ動きをしているのがわかると思います。

- [プログラミング初心者向け：DXRubyで 1ステップずつ作っていく「ブロック崩し」 - Qiita](https://qiita.com/noanoa07/items/9ebc059550c620ab223c)

```atari_en8.rb
require 'dxruby'

class Sprite
  def atari?(aite)
    x0     = self.x
    rad_x0 = self.image.width / 2
    cen_x0 = x0 + rad_x0

    y0     = self.y
    rad_y0 = self.image.height / 2
    cen_y0 = y0 + rad_y0

    x1     = aite.x
    rad_x1 = aite.image.width / 2
    cen_x1 = x1 + rad_x1

    y1     = aite.y
    rad_y1 = aite.image.height / 2
    cen_y1 = y1 + rad_y1

    # 半径は長径と短径の1/2に設定
    # 半径同士の和
    cir_dis = (rad_x0 + rad_y0) / 2 + (rad_x1 + rad_y1) / 2

    # 2乗で比較する
    cir_dis_2 = cir_dis **2
    dist_2 = (cen_x0 - cen_x1) ** 2 + (cen_y0 - cen_y1) ** 2
    cir_dis_2 >= dist_2
  end

  def atari_array(array)
    array.each do |a|
      if self.atari?(a)
        return a
      end
    end
    nil
  end
end

img_bar   = Image.new(100,  20, C_WHITE)
img_hwall = Image.new( 20, 480, C_BLUE)
img_vwall = Image.new(640,  20, C_BLUE)
img_ball  = Image.new( 20,  20).circle_fill(10, 10, 10, C_RED)
img_block = Image.new(28, 28).circle_fill(14, 14, 14, C_GREEN)   # ブロックを円に
img_block_y = Image.new(28, 28).circle_fill(14, 14, 14, C_YELLOW)   # ブロックを円に

bar   = Sprite.new(  0, 460, img_bar)
lwall = Sprite.new(  0,   0, img_hwall)
rwall = Sprite.new(620,   0, img_hwall)
twall = Sprite.new(  0,   0, img_vwall)

walls = [bar, lwall, rwall, twall]

ball  =  Sprite.new(300, 400, img_ball)
dx =  2
dy = -2

def move(sprite, speed_x, speed_y)
  sprite.x += speed_x
  sprite.y += speed_y
end

blocks = []
20.times do |x|       # ブロックの組み方を少し変更
  5.times do |y|
    blocks << Sprite.new(21 + 30 * x, 21 + 30 * y, img_block)
  end
end


Window.loop do
  bar.x = Input.mouse_pos_x
  Sprite.draw(walls)

  move(ball, dx, 0)
  if ball === walls
    ball.x -= dx
    dx = -dx
  end
  coll_x = ball.atari_array(blocks)
  if coll_x
    coll_x.image = img_block_y
    coll_x.draw     #一瞬色が変わって表示
    coll_x.vanish   #消える
    ball.x -= dx
    dx = -dx
  end

  move(ball, 0, dy)
  if ball=== walls
    ball. y -= dy
    dy = -dy
  end
  coll_y = ball.atari_array(blocks)
  if coll_y
    coll_y.image = img_block_y
    coll_y.draw     #一瞬色が変わって表示
    coll_y.vanish   #消える
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="atari_en8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/1be86059-960c-e56a-b399-9493ba0f536d.png">


# 参考
[プログラミング初心者向け：DXRubyで 1ステップずつ作っていく「ブロック崩し」 - Qiita](https://qiita.com/noanoa07/items/9ebc059550c620ab223c)
で作った「ブロック崩し」のプログラムです。

```block28.rb
require 'dxruby'

img_bar   = Image.new(100,  20, C_WHITE)
img_hwall = Image.new( 20, 480, C_BLUE)
img_vwall = Image.new(640,  20, C_BLUE)
img_ball  = Image.new( 20,  20).circle_fill(10, 10, 10, C_RED)
img_block = Image.new( 58,  18, C_GREEN)
img_block_y = Image.new( 58,  18, C_YELLOW)

bar   = Sprite.new(  0, 460, img_bar)
lwall = Sprite.new(  0,   0, img_hwall)
rwall = Sprite.new(620,   0, img_hwall)
twall = Sprite.new(  0,   0, img_vwall)

walls = [bar, lwall, rwall, twall]

ball  =  Sprite.new(300, 400, img_ball)
dx =  2
dy = -2

def move(sprite, speed_x, speed_y)
  sprite.x += speed_x
  sprite.y += speed_y
end

blocks = []
10.times do |x|
  5.times do |y|
    blocks << Sprite.new(21 + 60 * x, 21 + 20 * y, img_block)
  end
end


Window.loop do
  bar.x = Input.mouse_pos_x
  Sprite.draw(walls)

  move(ball, dx, 0)
  if ball === walls
    ball.x -= dx
    dx = -dx
  end
  coll_x = ball.check(blocks)
  if coll_x[0]
    coll_x[0].image = img_block_y
    coll_x[0].draw     #一瞬色が変わって表示
    coll_x[0].vanish   #消える
    ball.x -= dx
    dx = -dx
  end

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end
  coll_y = ball.check(blocks)
  if coll_y[0]
    coll_y[0].image = img_block_y
    coll_y[0].draw     #一瞬色が変わって表示
    coll_y[0].vanish   #消える
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c5de26a4-2112-311b-f8ff-301b7332d7bd.png">