DXRuby：「当たり判定」を自分で作ってみよう　C. 色で判定する

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


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

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

の内の
`C. 色で判定する`
になります。

<img width="50%" alt="atari_iro7b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/6faf017c-ebdb-ef59-f5e7-867dae7a4f32.png">

前の記事
・[DXRuby：「当たり判定」を自分で作ってみよう　B. 円の中心からの距離で判定する - Qiita](https://qiita.com/noanoa07/items/093989a7cc9c2853c11b)

次の記事
・[プログラミングの基礎力をつける：なるべく基本命令だけで作る「ブロック崩し」 on DXRuby - Qiita](https://qiita.com/noanoa07/items/f4c559d2e63507694f62)



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

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


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



# プログラム解説
## C. 色で判定する
→ 「ブロック崩し」追加課題 1c)；衝突判定の自作（色） - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2052899.html

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

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

```atari_iro1.rb
require 'dxruby'

image0 = Image.new( 50,  50, C_WHITE)
image1 = Image.new(200, 100, C_WHITE)
image2 = Image.new(200, 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 = (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_iro1a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/ce6723a2-3ba3-5e2c-f05a-e866dafc59e5.png">

<img width="50%" alt="atari_iro1b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/bf3bb7dd-e97c-a853-70d2-969279dfc686.png">


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

DXRubyでは、座標(x, y)の色を取得する方法は、`イメージ[x, y]`しかありませんので、これを使うことにします。これを使えば、

`イメージ[x, y] == C_DEFAULT` で座標(x,y)が透明かどうかを比較できます。

手順としては、まず、表示するウィンドウと同じサイズの透明な衝突判定用のイメージ`$screen`を用意します。（`$`でグローバル変数にしています。）`$screen[x, y]`で座標(x,y)の色を取得して、`色がある`/`透明`を`衝突している`/`していない`の判定に使います。

この部分を`atari?(x,y)`として作ってみます。

```ruby
$screen = Image.new(640, 480)

def atari?(x, y)
  if $screen[x,y] == C_DEFAULT   # 位置(x,y)が透明かどうかで衝突判定
    return false
  end
  true
end
```

これだけだと、点(x, y)しか判定できないので、スプライト画像を判定できるように`atari_sprite?(jibun, aite)`を作ります。

これにはDXRubyの`イメージ.draw(x, y, コピーしたいイメージ画像)`を使います。これで、あるイメージの上に別のイメージ画像をコピーできます。

```ruby
def atari_sprite?(jibun, aite)
  x0  = jibun.x
  xx0 = x0 + jibun.image.width

  y0  = jibun.y
  yy0 = y0 + jibun.image.height

  $screen.clear                            # $screenは毎回 clearする
  $screen.draw(aite.x, aite.y, aite.image) # $screenに描画して衝突判定

  atari?(x0,  y0) || atari?(xx0,  y0) ||
  atari?(x0, yy0) || atari?(xx0, yy0)
end
```

ここで、`$screen.clear`は、毎回`$screen`を`透明`に戻しています。
また、衝突判定は四角形`jibun`の四隅が透明かどうかで判定しています。

```ruby
atari?(x0,  y0) || atari?(xx0,  y0) ||
atari?(x0, yy0) || atari?(xx0, yy0)
```

そして、実際の画面の描画では、この`$screen`は使わず、普通にウィンドウに`スプライト.draw`、`Window.draw_font`を使います。


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

→ DXRubyリファレンス：API INDEX；class Image　：[]，draw，clear
http://mirichi.github.io/dxruby-doc/api/Image.html

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

→ Re: 描画処理の改善法 - DXRuby 掲示板 322 mirichi（2015/05/31 11:49）
http://dxruby.osdn.jp/bbs_/

```atari_iro2.rb
require 'dxruby'

$screen = Image.new(640, 480)

def atari?(x, y)
  if $screen[x,y] == C_DEFAULT   # 位置(x,y)が透明かどうかで衝突判定
    return false
  end
  true
end

def atari_sprite?(jibun, aite)
  x0  = jibun.x
  xx0 = x0 + jibun.image.width

  y0  = jibun.y
  yy0 = y0 + jibun.image.height

  $screen.clear                            # $screenは毎回 clearする
  $screen.draw(aite.x, aite.y, aite.image) # $screenに描画して衝突判定

  atari?(x0,  y0) || atari?(xx0,  y0) ||
  atari?(x0, yy0) || atari?(xx0, yy0)
end

image0 = Image.new( 50,  50, C_WHITE)
image1 = Image.new(200, 100, C_WHITE)
image2 = Image.new(200, 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_sprite?(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_iro2a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c92fac76-d6d1-c691-67d5-1796386978fd.png">

<img width="50%" alt="atari_iro2b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/77ae5ce8-9010-8391-ecc7-f7e343b0bcee.png">


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

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

```atari_iro3.rb
require 'dxruby'

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

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

block1 = Sprite.new( 10, 200, image1)
block2 = Sprite.new(250, 200, 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 = (ball === blocks)
  p result

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

  Sprite.draw(blocks)
end
```

<img width="50%" alt="atari_iro3a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e39b94b0-1143-c226-5ae0-de4ee2fda50d.png">

<img width="50%" alt="atari_iro3b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/57aedb36-f63b-8a66-676d-055f09a1007f.png">

<img width="50%" alt="atari_iro3c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/85beef96-4711-aef2-7847-2668fab713e9.png">

<img width="50%" alt="atari_iro3d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/0c5a6550-2e5c-04ad-0443-d9a9bc413722.png">


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

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

```atari_iro4.rb
require 'dxruby'

$screen = Image.new(640, 480)

def atari?(x, y)
  if $screen[x,y] == C_DEFAULT
    return false
  end
  true
end

def atari_sprite?(jibun, aite)
  x0  = jibun.x
  xx0 = x0 + jibun.image.width

  y0  = jibun.y
  yy0 = y0 + jibun.image.height

  $screen.clear
  $screen.draw(aite.x, aite.y, aite.image)

  atari?(x0,  y0) || atari?(xx0,  y0) ||
  atari?(x0, yy0) || atari?(xx0, yy0)
end

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

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

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

block1 = Sprite.new( 10, 200, image1)
block2 = Sprite.new(250, 200, 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_iro4a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d86fe3b0-6d82-9509-dadb-0fe453fb619b.png">

<img width="50%" alt="atari_iro4b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/6f357c5f-8d06-3037-ab30-dc441883c675.png">

<img width="50%" alt="atari_iro4c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c164c209-16f5-658c-7571-3ecc1c61f2a1.png">

<img width="50%" alt="atari_iro4d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/236a085f-a961-c8a1-d4c2-672578c4b512.png">


### C-3a. `check`を使った準備（atari_iro5.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_iro5.rb
require 'dxruby'

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

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

block1 = Sprite.new( 10, 200, image1)
block2 = Sprite.new(250, 200, 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.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_iro5a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/ef95cb4a-2f64-90be-62a5-8fe4711ee510.png">

<img width="50%" alt="atari_iro5b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/bd908f34-3c3e-7457-a39c-631e8f9c0aec.png">

<img width="50%" alt="atari_iro5c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/06ed6a80-4d87-d02f-2b93-abb1b120cf28.png">

<img width="50%" alt="atari_iro5d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/290cf1e9-d06f-3069-12c8-82a4efe4a47b.png">


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

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

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

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

```atari_iro6.rb
require 'dxruby'

$screen = Image.new(640, 480)

def atari?(x, y)
  if $screen[x,y] == C_DEFAULT
    return false
  end
  true
end

def atari_sprite?(jibun, aite)
  x0  = jibun.x
  xx0 = x0 + jibun.image.width

  y0  = jibun.y
  yy0 = y0 + jibun.image.height

  $screen.clear
  $screen.draw(aite.x, aite.y, aite.image)

  atari?(x0,  y0) || atari?(xx0,  y0) ||
  atari?(x0, yy0) || atari?(xx0, yy0)
end

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

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

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

block1 = Sprite.new( 10, 200, image1)
block2 = Sprite.new(250, 200, 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_iro6a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/7f543921-c2c3-c285-255f-ccab696575ae.png">

<img width="50%" alt="atari_iro6b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/f5e796e2-6440-6eda-861b-58942ae8cab6.png">

<img width="50%" alt="atari_iro6c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/3f7088ed-34a6-fa45-f2ad-a48c5a179c37.png">

<img width="50%" alt="atari_iro6d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/51d8c0a5-336b-58d6-baf7-e1c700182844.png">


### C-4. 自作の当たり判定（色）を`Spriteクラスのメソッド`にする（atari_iro7.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?(x, y)
    if $screen[x,y] == C_DEFAULT
      return false
    end
    true
  end

  def atari_sprite?(aite)
    x0  = self.x
    xx0 = x0 + self.image.width

    y0  = self.y
    yy0 = y0 + self.image.height

    $screen.clear
    $screen.draw(aite.x, aite.y, aite.image)

    atari?(x0,  y0) || atari?(xx0,  y0) ||
    atari?(x0, yy0) || atari?(xx0, yy0)
  end

  def atari_array(array)
    array.each do |aite|
      return aite if atari_sprite?(aite)
    end
    nil
  end
end
```

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

```atari_iro7.rb
require 'dxruby'

$screen = Image.new(640, 480)

class Sprite
    def atari?(x, y)
      if $screen[x,y] == C_DEFAULT
        return false
      end
      true
    end
  
    def atari_sprite?(aite)
      x0  = self.x
      xx0 = x0 + self.image.width
  
      y0  = self.y
      yy0 = y0 + self.image.height
  
      $screen.clear
      $screen.draw(aite.x, aite.y, aite.image)
  
      atari?(x0,  y0) || atari?(xx0,  y0) ||
      atari?(x0, yy0) || atari?(xx0, yy0)
    end
  
    def atari_array(array)
      array.each do |aite|
        return aite if atari_sprite?(aite)
      end
      nil
    end
end

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

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

block1 = Sprite.new( 10, 200, image1)
block2 = Sprite.new(250, 200, 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_iro7a.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/815835d6-013b-40ec-1d9d-33468d4a57d3.png">

<img width="50%" alt="atari_iro7b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/6faf017c-ebdb-ef59-f5e7-867dae7a4f32.png">

<img width="50%" alt="atari_iro7c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d9967640-1a7f-c6ac-85aa-be2a1333a0c0.png">

<img width="50%" alt="atari_iro7d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/01985835-8c8a-d833-fbe1-24b813c8df54.png">


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

元の`===`と`check.first`を同じ動きをしているのがわかると思います。

```atari_iro8.rb
require 'dxruby'

$screen = Image.new(640, 480)

class Sprite
    def atari?(x, y)
      if $screen[x,y] == C_DEFAULT
        return false
      end
      true
    end
  
    def atari_sprite?(aite)
      x0  = self.x
      xx0 = x0 + self.image.width
  
      y0  = self.y
      yy0 = y0 + self.image.height
  
      $screen.clear
      $screen.draw(aite.x, aite.y, aite.image)
  
      atari?(x0,  y0) || atari?(xx0,  y0) ||
      atari?(x0, yy0) || atari?(xx0, yy0)
    end
  
    def atari_array(array)
      array.each do |aite|
        return aite if atari_sprite?(aite)
      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( 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.atari_array(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.atari_array(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_iro8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/7829fb2d-6d0c-e69d-1b80-5fd1ab3115c2.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">