プログラミング初心者向け：DXRubyで 1ステップずつ作っていく「ブロック崩し」

# 概要
この記事は中学高校生向けプログラミング教室の教材として作ったものを一部改変したものです。
Rubyでプログラミングの初歩を学んだ次のステップとして、ゲームライブラリDXRubyを使って「ブロック崩し」ゲームを作っていきます。

0から少しずつ「ブロック崩し」を作っていきます。Rubyだと完成しても100行足らずで「ブロック崩し」ができてしまいます。

<img width="50%" alt="ブロック崩し」イメージ/ block30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/94849af6-d739-027f-18e4-11b6bd82900e.png">

前の記事
・[Ruby用2Dゲームライブラリ DXRuby：使い方の初歩 - Qiita](https://qiita.com/noanoa07/items/bced6519d9b53685b651)

続編
・[DXRuby：「当たり判定」を自分で作ってみよう - Qiita](https://qiita.com/noanoa07/items/b7d647bba20116c41a77)

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



# 技術解説
## ソースコード
https://github.com/noanoa07/dxruby_blocks

## 使用ライブラリ
Windows向けRuby用2Dゲームライブラリ`DXRuby`を使用します。
バージョン`1.4.2`以上を想定しています。

### `1.4.2`より前のバージョンとの主な相違点

- `Window.loop`が複数置ける

- マウス位置を取得する`Input.mouse_pos_x`、`Input.mouse_pos_y`の新しい書き方として、`Input.mouse_x`、`Input.mouse_y`が追加

→ DXRuby 1.4.6：更新履歴

http://mirichi.github.io/dxruby-doc/CHANGELOG.html

### DXRubyインストールの注意点
→ DXRuby 1.4.6 をWindows10で使う時の注意点とインストール方法 - noanoa07 - Qiita
https://qiita.com/noanoa07/items/0ce14c2404df38de94b7

## 参考サイト
- DXRuby のホームページ
http://dxruby.osdn.jp

- DXRuby 1.4.6 リファレンスマニュアル
http://mirichi.github.io/dxruby-doc/index.html

困ったときは、このページの「チュートリアル」と「マニュアル」にだいたい書いてあります。

- DXRuby 1.4.1 リファレンスマニュアル
http://dxruby.osdn.jp/DXRubyReference/20095313382446.htm

古いバージョンのリファレンスも役に立つときがあります。

- DXRubyで 0から作る「ブロック崩し」 - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2045851.html

このテキストのブログ記事での解説です。


## オリジナル
※「2014-03-17 松江Ruby会議05に参加してきた - mirichiの日記」より改変

　http://d.hatena.ne.jp/mirichi/20140317/p1


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



# プログラム解説
## 1．DXRubyの練習
→ [Ruby用2Dゲームライブラリ DXRuby：使い方の初歩 - Qiita](https://qiita.com/noanoa07/items/bced6519d9b53685b651)
を見てください。

## 2．「ブロック崩し」を作る
いよいよ「ブロック崩し」を作っていきます。

### 2-1． バーを出す（block01.rb）
横100、縦20大きさの白い長方形を、ボールを打ち返すバーとして作ります。

まず、 `Image.new` でイメージを作成します。さらに、ボールとの衝突判定をするために `Spite.new` でスプライト化します。初期位置は、x = 0、ｙ = 460にしますが、実際の描画では`x`はマウスの横位置(mouse_pos_x)に追従するようにします。

ウィンドウの初期サイズは、指定しないと横640、縦480になります。そのため、バーの縦位置`y`はウィンドウの一番下480に合わせるため、バーの縦幅を引いた`480 - 20 = 460`にしています。

バーを表示させるには、`Window.loop do 〜 end`の中で`draw`メソッド（命令）を使います。

```block01.rb
require 'dxruby'

img_bar = Image.new(100, 20, C_WHITE)

bar = Sprite.new(0, 460, img_bar)


Window.loop do
  bar.x = Input.mouse_pos_x

  bar.draw
end
```

<img width="50%" alt="block01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/668f7c8a-1eca-e833-27bf-7429c17d9bb2.png">


### 2-2． 壁を出す（左側）（block02.rb）
左側の縦の壁を作ります。まず、横20、縦は（ウィンドウの縦幅と同じ）480の大きさの青い長方形のイメージ`img_hwall`を作ります。

これを壁として、ボールとの衝突判定をするためにスプライト化します（`lwall`）。位置は、左上隅（x = 0、ｙ = 0）に配置します。

```block02.rb
require 'dxruby'

img_bar   = Image.new(100,  20, C_WHITE)
img_hwall = Image.new( 20, 480, C_BLUE)

bar   = Sprite.new(0, 460, img_bar)
lwall = Sprite.new(0,   0, img_hwall)


Window.loop do
  bar.x = Input.mouse_pos_x
  bar.draw

  lwall.draw
end
```

<img width="50%" alt="block02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d5b0339f-b7bb-6c0a-a965-210e27e91174.png">


### 2-3． 壁を出す（右側も）（block03.rb）
右側の縦の壁を作ります。左側の壁と同じ大きさなので、同じイメージ`img_hwall`を使ってスプライト化し（`rwall`）、右上隅（x = 620、y = 0）に配置します。

右壁の横位置`x`はウィンドウ幅640から壁の横幅20を引いた`640 - 20 = 620`にします。

```block03.rb
require 'dxruby'

img_bar   = Image.new(100,  20, C_WHITE)
img_hwall = Image.new( 20, 480, C_BLUE)

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


Window.loop do
  bar.x = Input.mouse_pos_x
  bar.draw

  lwall.draw
  rwall.draw
end
```

<img width="50%" alt="block03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/0f72f77c-98ef-ada3-664e-2a8b893dac99.png">


### 2-4． 壁を出す（上側も）（block04.rb）
上側の横の壁を作ります。まず、横は（ウィンドウの横幅と同じ）640、縦20の大きさの白い長方形のイメージ`img_vwall`を作ります。

これもボールとの衝突判定をするためにスプライト化します（`twall`）。位置は、左上隅（x = 0、ｙ = 0）に配置します。

```block04.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)

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)


Window.loop do
  bar.x = Input.mouse_pos_x
  bar.draw

  lwall.draw
  rwall.draw
  twall.draw
end
```

<img width="50%" alt="block04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/03f42456-d41e-c113-1d40-726da0ee0d50.png">


### 2-5． 壁とバーをまとめて描く：配列（block05.rb）
壁とバーの描画が4行と増えたので、まとめて描くようにします。

バーと壁をまとめて配列`walls`にします。そして、スプライトの配列をまとめて描画できる`Sprite.draw`で一気に表示させます。


```block05.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)

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]


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

<img width="50%" alt="block05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/8cbe279d-574d-bedd-9cb3-9533af1b1f49.png">


### 2-6． ボールを出す（block06.rb）
ボールを作ります。横20、縦20の正方形の中に、中心が x=10、y = 10、半径が10（つまり正方形目一杯）の赤い円のイメージ`img_ball`を作ります。

壁、バーと衝突判定するためにスプライト化します（`ball`）。初期位置はとりあえず x = 300、y = 400 にして、表示します。

```block06.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)

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)


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

  ball.draw
end
```

<img width="50%" alt="block06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/26a68aa4-fe66-ca50-b6c2-70d0304aacd7.png">


### 2-7． ボールを動かす（横方向）（block07.rb）
ボールを横方向（x方向）に動かします。（xは右がプラス方向）

スピード`dx`を2として、`ball`の`x位置`にloopで回ってくる（1/60秒）毎に`dx`分を足していきます。

```block07.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)

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


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

  ball.x = ball.x + dx

  ball.draw
end
```

<img width="50%" alt="block07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d545ba04-48fb-6cfb-35cd-c5b1ab742f45.png">


### 2-8． ボールを動かす（横方向）：別の書き方（block08.rb）

`ball.x = ball.x + dx`を別の書き方である、

`ball.x += dx`に書き換えてみます。同じことですが、慣れればこちらの方が見やすいかも?


```block08.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)

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


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

  ball.x += dx

  ball.draw
end
```

<img width="50%" alt="block08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/1981e6bf-d1bc-4cfd-7e6e-80163c3fe247.png">


### 2-9． ボールを動かす（縦方向）（block09.rb）
今度は縦方向（y方向）に動かします。（yは下がプラス方向）

いったん横方向のスピード`dx`は0にして、縦方向のスピード`dy`を-2にします。`ball`の`y位置`にloopで回ってくる毎に`dy`分を足していきます。

```block09.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)

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 =  0
dy = -2


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

  ball.x += dx
  ball.y += dy

  ball.draw
end
```

<img width="50%" alt="block09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/691152d5-c153-b6a3-573a-cc156c1c6790.png">


### 2-10． ボールを動かす（縦横方向）（block10.rb）
ボールの横方向のスピード`dx`を2、縦方向のスピード`dy`を-2にすると、斜めに動いていきます。

```block10.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)

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


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

  ball.x += dx
  ball.y += dy

  ball.draw
end
```

<img width="50%" alt="block10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/5ab9ee34-be86-cadc-9013-7fcfa7d2507e.png">


### 2-11． 動かすをまとめる（block11.rb）
横に動かす`ball.x += dx`と縦に動かす`ball.y += dy`は、いつも一緒に使うので、まとめて書いてみます。

ここでは`move`という命令を作ります（`def 〜 end`で定義）
。引数としては、ボールのような動かすもの（スプライト）、横方向（x方向）のスピード、縦方向（y方向）のスピードを指定します。

```block11.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)

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


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

  move(ball, dx, dy)

  ball.draw
end
```

<img width="50%" alt="block11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e645a4eb-1138-775a-f8c5-7164772007cb.png">


### 2-12． ボールが跳ね返る（横方向）（block12.rb）
ボールを跳ね返らせます。まずは、縦方向（y方向）のスピード`dy`を0にして、横方向（x方向）だけ動かします。

衝突判定には`===`を使います。もし、ボール`ball`と壁やバー`walls`が衝突したら、ボールのx位置`ball.x`を衝突前の位置に戻し（`ball.x -= dx`）、ボールのx方向のスピード`dx`のプラス/マイナスを反対にして、逆方向に動くようにします。

```block12.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)

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


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

  ball.draw
end
```

<img width="50%" alt="block12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/49ff85a1-a5be-5e05-36b5-c57500d8d06b.png">


### 2-13． ボールが跳ね返る（縦方向）（block13.rb）
今度は縦方向（y方向）だけ動かします。

```block13.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)

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


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

  move(ball, 0, 0)      #縦方向だけ動かす
  if ball === walls
    ball.x -= dx
    dx = -dx
  end

  move(ball, 0, dy)      #縦方向だけ動かす
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw
end
```

<img width="50%" alt="block13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/a3152932-c197-9685-51c8-7295bea21514.png">


### 2-14． ボールが跳ね返る（縦横方向）（block14.rb）
縦横ともに動かして、衝突したら跳ね返らせます。ちょっと「ブロック崩し」の雰囲気が出てきましたね。

ここでは、まずx方向に動かして、ぶつかったらx方向だけ跳ね返って、次にy方向に動かして、ぶつかったらy方向だけ跳ね返る書き方をしています。

なぜ、x方向、y方向同時に動かして、ぶつかったら跳ね返る書き方にしていないのでしょうか？自分で試して考えてみてください。

```block14.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)

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


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw
end
```

<img width="50%" alt="block14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/57470984-c7b1-73f3-79ae-57b1dc4b1575.png">


### 2-15． ブロックを出す（1個）（block15.rb）
ブロックを作っていきます。まずは1個。

ブロックは横58、縦18の大きさの緑の長方形のイメージ`img_block`を作ります。さらに、ボールとの衝突判定をするためにスプライト化します（`block_00`）。

横の大きさは、横に10個置くことにして、(ウィンドウ横幅640 - 左右の壁の厚み 20 * 2) / 10 = 60 に、隣同士の隙間を左右 1ずつとって 58にしています。

位置は、左上の壁の内側（x = 20, y = 20）から横、縦とも 1だけ隙間を空けて、x = 21、ｙ = 21に配置します。


```block15.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)

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

block_00 = Sprite.new(21, 21, img_block)


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  block_00.draw
end
```

<img width="50%" alt="block15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/3fb9deac-946f-994a-b0df-9124b04c4009.png">


### 2-16． ブロックを出す（2個）（block16.rb）
2個目のブロックは、同じ大きさのブロックをxを60だけ右にずらした位置に置きます。（ブロックの横幅は58なので少し隙間が空きます。）

```block16.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)

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

block_00 = Sprite.new(21     , 21, img_block)
block_01 = Sprite.new(21 + 60, 21, img_block)


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  block_00.draw
  block_01.draw
end
```

<img width="50%" alt="block16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/a7b41d22-457b-1712-52ab-468534acb9e8.png">


### 2-17． ブロックを出す（3個）（block17.rb）
同じく3個目のブロックを置きます。x位置は、ブロックの横幅58と隙間を見込んで60ずつずらしていきます。

```block17.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)

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

block_00 = Sprite.new(21         , 21, img_block)
block_01 = Sprite.new(21 + 60    , 21, img_block)
block_02 = Sprite.new(21 + 60 * 2, 21, img_block)


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  block_00.draw
  block_01.draw
  block_02.draw
end
```

<img width="50%" alt="block17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/0593cdb3-f1e0-4440-1dc9-312a0c041740.png">


### 2-18． ブロックを出す（5個）（block18.rb）
5個まで同様にブロックを置きます。

```block18.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)

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

block_00 = Sprite.new(21         , 21, img_block)
block_01 = Sprite.new(21 + 60    , 21, img_block)
block_02 = Sprite.new(21 + 60 * 2, 21, img_block)
block_03 = Sprite.new(21 + 60 * 3, 21, img_block)
block_04 = Sprite.new(21 + 60 * 4, 21, img_block)


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  block_00.draw
  block_01.draw
  block_02.draw
  block_03.draw
  block_04.draw
end
```

<img width="50%" alt="block18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/6ac94b45-d014-ef39-b8b8-53a56a53f254.png">


### 2-19． ブロックを出す（10個）（block19.rb）
横に10個置くとちょうどぴったりの幅です。

```block19.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)

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

block_00 = Sprite.new(21         , 21, img_block)
block_01 = Sprite.new(21 + 60    , 21, img_block)
block_02 = Sprite.new(21 + 60 * 2, 21, img_block)
block_03 = Sprite.new(21 + 60 * 3, 21, img_block)
block_04 = Sprite.new(21 + 60 * 4, 21, img_block)
block_05 = Sprite.new(21 + 60 * 5, 21, img_block)
block_06 = Sprite.new(21 + 60 * 6, 21, img_block)
block_07 = Sprite.new(21 + 60 * 7, 21, img_block)
block_08 = Sprite.new(21 + 60 * 8, 21, img_block)
block_09 = Sprite.new(21 + 60 * 9, 21, img_block)


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  block_00.draw
  block_01.draw
  block_02.draw
  block_03.draw
  block_04.draw
  block_05.draw
  block_06.draw
  block_07.draw
  block_08.draw
  block_09.draw
end
```

<img width="50%" alt="block19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/b824341b-16fc-2ac7-cd5f-be2cccd2b452.png">


### 2-20． ブロックを出す（まとめて表示する）（block20.rb）
ブロックを表示させる`draw`が10行にもなったので、まとめて描くようにします。

バーと壁を配列`walls`にまとめたように、10個のブロックを配列`blocks`にします。そして、`Sprite.draw`で一気に表示させます。


```block20.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)

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

block_00 = Sprite.new(21         , 21, img_block)
block_01 = Sprite.new(21 + 60    , 21, img_block)
block_02 = Sprite.new(21 + 60 * 2, 21, img_block)
block_03 = Sprite.new(21 + 60 * 3, 21, img_block)
block_04 = Sprite.new(21 + 60 * 4, 21, img_block)
block_05 = Sprite.new(21 + 60 * 5, 21, img_block)
block_06 = Sprite.new(21 + 60 * 6, 21, img_block)
block_07 = Sprite.new(21 + 60 * 7, 21, img_block)
block_08 = Sprite.new(21 + 60 * 8, 21, img_block)
block_09 = Sprite.new(21 + 60 * 9, 21, img_block)

blocks = [block_00, block_01, block_02, block_03, block_04,
          block_05, block_06, block_07, block_08, block_09]


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/bfc4827d-b53e-cae9-a632-7219c49a9c21.png">


### 2-21． ブロックを出す（まとめて作る）（block21.rb）
ブロックを作る方もまとめて一気に作るようにします。

まず、空の配列`blocks`を作ります。配列に追加していく`<<`メソッドを使って、ブロックを1つ作っては配列`blocks`に追加していきます。

10回繰り返すので、`10.times do 〜 end`を使って、1回毎に`x`を増やすことで横位置をずらしたブロックを作ります。（`x`は 0, 1, 2, ... , 9 と変わっていく）

```block21.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)

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|
  blocks << Sprite.new(21 + 60 * x, 21, img_block)
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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/67992654-93fe-5859-c188-58032918b0e5.png">


### 2-22． ブロックを出す（2段目も作る）（block22.rb）
2段目のブロックも作っていきます。2段目はyの位置を20大きくします。するとブロックの縦幅は18なので、少し隙間が空きます。

```block22.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)

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|
  blocks << Sprite.new(21 + 60 * x, 21, img_block)
end

blocks << Sprite.new(21         , 21 + 20, img_block)
blocks << Sprite.new(21 + 60 * 1, 21 + 20, img_block)
blocks << Sprite.new(21 + 60 * 2, 21 + 20, img_block)


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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/fb2e9b19-165b-de9d-e5d1-1aea7bb7edce.png">


### 2-23． ブロックを出す（2段目もまとめて作る）（block23.rb）
2段目の作り方も、1段目と同じく`10.times do 〜 end`を使って書きます。

```block23.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)

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|
  blocks << Sprite.new(21 + 60 * x, 21, img_block)
end

10.times do |x|
  blocks << Sprite.new(21 + 60 * x, 21 + 20, img_block)
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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c6dd666e-7f26-63b8-fc64-4d9d41d34f57.png">


### 2-24． ブロックを出す（5段目まで作る）（block24.rb）
5段目まで作りました。

```block24.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)

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|
  blocks << Sprite.new(21 + 60 * x, 21, img_block)
end

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

10.times do |x|
  blocks << Sprite.new(21 + 60 * x, 21 + 20 * 2, img_block)
end

10.times do |x|
  blocks << Sprite.new(21 + 60 * x, 21 + 20 * 3, img_block)
end

10.times do |x|
  blocks << Sprite.new(21 + 60 * x, 21 + 20 * 4, img_block)
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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/699c320b-51f6-0779-9355-e5dbfc91a681.png">


### 2-25． ブロックを出す（5段目までまとめて作る）（block25.rb）
`10.times do 〜 end`が5回出てきたので、これをまとめてみます。

`10.times do 〜 end`の中に、`5.times do 〜 end`を入れて、2重の形にします。

```block25.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)

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

  move(ball, 0, dy)
  if ball === walls
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/df9f2832-b7b4-c34f-65ce-d01d5c98bb3f.png">


### 2-26． ブロックとの衝突判定(当たったらブロックは色が変わる）（block26.rb）
ボールとブロックの衝突判定をします。壁やバーと違って、ぶつかったブロックは消す必要があるので、どのブロックにぶつかったか知る必要があります。そこで、`===`ではなく`check`を使います。

`check`は、衝突判定するだけでなく、衝突したものを配列で返します。それを配列`coll_x`や`coll_y`に代入すると、配列に1つでも要素が入っていたら衝突したと判定できます。（同時に複数衝突していたらその数だけ配列に入ります。）

つまり、`coll_x[0]`や`coll_y[0]`に何か入っていたら、ブロックとぶつかっているし、それがぶつかった（0番目の）ブロックです。ここでは、ぶつかったブロックを黄色いブロックに変えることで分かりやすくしています。

```block26.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
  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
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d732a568-f262-b5c6-e1f0-d4aa85838e75.png">


### 2-27． ブロックとの衝突判定(当たったブロックの色が変わり、跳ね返る)（block27.rb）
ブロックとぶつかったらボールが跳ね返るようにします。

```block27.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
    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
    ball. y -= dy
    dy = -dy
  end

  ball.draw

  Sprite.draw(blocks)
end
```

<img width="50%" alt="block27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/326edabd-e1ba-49fb-347b-a260a42a96e2.png">


### 2-28． 当たったブロックは消える（一瞬色が変わる）；一応完成（block28.rb）
ぶつかったブロックを消します。そのためには`vanish`を使います。

これで「ブロック崩し」は一応完成です！

```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">



# 応用問題
追加の課題として、いくつか考えてみました。気になったものをやってみましょう。

- A. 「ブロック崩し」を改良・発展させてみよう
- B. クラス・オブジェクト指向を使ってみよう
- C. DXRubyの衝突判定を自作してみよう
- D. なるべく基本命令だけでブロック崩しを作ってみよう

→「ブロック崩し」の追加課題 - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2046181.html


## A. 「ブロック崩し」を改良・発展させてみよう
「ブロック崩し」を改良・発展させてみましょう。

以下はほんの一例です。各自、自由に発展させてみてください。

### A-1. 動作を改善する
作った「ブロック崩し」を動かしてみて、動きが気になるところを直してみましょう。


### A-2． タイトルを表示する（block29.rb）
ウィンドウの左上にタイトルを表示してみます。`Window.caption =`を使います。

```block29.rb
require 'dxruby'

GAME = "ブロック崩し" #定数 文字列
ver = 0.1           #変数 数
name = "作者名"      #変数 文字列

Window.caption = GAME + "ゲーム #{ver} by" + name

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="block29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/257619a6-d196-7790-25c4-26362f5ba8a9.png">


### A-3． 画面に文字を表示する（block30.rb）
画面に文字を表示してみましょう。

`Window.draw_font(x位置, y位置, 文字列, font, {:color => 文字色)`のように指定します。

残りブロック数を知るには、ブロックの配列`blocks`に`.size`します。ただし、`blocks.size`の前に、衝突して無効化されたブロックを`Sprite.clean`で削除しておかなくてはいけません。

```block30.rb
require 'dxruby'

GAME = "ブロック崩し" #定数 文字列
ver = 0.1           #変数 数
name = "作者名"      #変数 文字列

Window.caption = GAME + "ゲーム #{ver} by" + name

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

font = Font.new(24)

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)

  Sprite.clean(blocks)
  string = "残りブロックは #{blocks.size}個です。"
  puts string
  Window.draw_font(20, 200, string, font, {:color => C_YELLOW})
end
```

<img width="50%" alt="block30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/94849af6-d739-027f-18e4-11b6bd82900e.png">


### A-4． ゲームオーバー画面を追加する，ESCキーで終了（block31.rb）
ゲームオーバー画面を追加してみます。

ボールのy位置`ball_y`が画面より下に行ってしまったら（ウィンドウの縦幅480より大きくなったら）、`break`で`Window.loop do 〜 end`から抜けます。そして、次の`Window.loop do 〜 end`が始まり、ここでゲームオーバー画面を表示します。

また、`ESC`キーが押されたら`Input.key_down?(K_ESCAPE)`で検出して、やはり`break`で`Window.loop do 〜 end`を抜けることでプログラムを終了させるようにします。

```block31.rb
require 'dxruby'

GAME = "ブロック崩し" #定数 文字列
ver = 0.1           #変数 数
name = "作者名"      #変数 文字列

Window.caption = GAME + "ゲーム #{ver} by" + name

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

font = Font.new(24)

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)

  Sprite.clean(blocks)
  string = "残りブロックは #{blocks.size}個です。"
  Window.draw_font(20, 200, string, font, {:color => C_YELLOW})

  puts ball.y
  if ball.y >= 480
    break                # breakで loopを抜ける
  end
end

Window.loop do
  Window.bgcolor= C_WHITE
  Window.draw_font(200, 200, "ゲームオーバー", font, {:color => C_BLACK})
  Window.draw_font(2000, 230, "（ESCキーで終了）", font, {:color => C_BLACK})
  if Input.key_down?(K_ESCAPE)
    exit                 # exit でプログラムを終了する
  end
end
```

<img width="50%" alt="block31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/fab4706a-e5fe-da4c-9c88-6b2aa6e45452.png">


## B. クラス・オブジェクト指向を使ってみよう（block_class_oo.rb）
クラスにまとめたり、オブジェクト指向を使った書き方に変えてみましょう。

クラスやオブジェクト指向については、ここでは説明をしませんが、プログラミングの重要な考え方なので、ぜひ勉強してみてください。

以下に、一例を示します。

→「ブロック崩し」追加課題3；クラス・オブジェクト指向を使ってみよう - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2051658.html

```block_class_oo.rb
# ブロッック崩し
#--------------------------------------------------------------
# Sprite + Class版
#--------------------------------------------------------------
require 'dxruby'

# 棒
class Bar < Sprite
  def initialize(x = 0, y = 460)
    self.x = x
    self.y = y
    self.image = Image.new(100,  20, C_WHITE)
  end
  def update
    self.x = Input.mouse_pos_x
  end
end


# 壁
class Walls < Array
  def initialize
    self << Wall.new(  0, 0,  20, 480)   # 左側
    self << Wall.new(  0, 0, 640,  20)   # 上側
    self << Wall.new(620, 0,  20, 480)   # 右側
  end
  def draw
    Sprite.draw(self)
  end
end

class Wall < Sprite
  def initialize(x, y, dx, dy)
    self.x = x
    self.y = y
    self.image = Image.new(dx, dy, C_WHITE)
  end
end


# ブロック
class Blocks < Array
  def initialize
    colors = [C_BLUE, C_YELLOW, C_WHITE, C_RED, C_GREEN]
    5.times do |y|
      10.times do |x|
        self << Block.new(21 + 60 * x , 21 + 20 * y, colors[y])
      end
    end
  end
  def draw
    self.each do |b|
      b.draw
    end
  end
end

class Block < Sprite
  def initialize(x, y, c)
    self.x = x
    self.y = y
    self.image = Image.new(58, 18, c)
  end
end


# ボール
class Ball < Sprite
  def initialize(x = 300, y = 400)
    self.x = x
    self.y = y
    self.image = Image.new(20, 20).circle_fill(10, 10, 10, C_WHITE)
    @dx =  4
    @dy = -4
  end

  def update(walls, bar, blocks)

    # 横方向への移動
    self.x += @dx

    # 壁または棒に衝突
    if self === walls or self === bar
      self.x -= @dx
      @dx    *= -1
    end

    # ブロックに衝突
    hit = self.check(blocks).first
    if hit != nil
      hit.vanish
      self.x -= @dx
      @dx    *= -1
    end

    # 縦方向への移動
    self.y += @dy

    # 壁または棒に衝突
    if self === walls or self === bar
      self.y -= @dy
      @dy    *= -1
    end

    # ブロックに衝突
    hit = self.check(blocks).first
    if hit != nil
      hit.vanish
      self.y -= @dy
      @dy    *= -1
    end

  end
end


# ブロック崩しゲーム
class Game
  def initialize
    @walls  = Walls.new    # 壁
    @bar    = Bar.new      # 棒
    @ball   = Ball.new     # ボール
    @blocks = Blocks.new   # ブロック
  end

  def play
    Window.loop do
      @walls.draw
      @bar.update
      @bar.draw
      @ball.update(@walls, @bar, @blocks)
      @ball.draw
      @blocks.draw

      break if Input.key_push?(K_ESCAPE)
    end
  end
end



#
# メイン
#
game = Game.new   # ゲーム初期化
game.play         # ゲーム開始
```

<img width="50%" alt="block_oo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d61076b8-9ce8-8f1c-3952-bb918c83a719.png">


## C. DXRubyの衝突判定を自作してみよう
今回作った「ブロック崩し」では、衝突判定に DXRuby の === や check を使いました。
とても便利な機能ですが、自分で作るとしたらどうしたらよいでしょうか？ 

判定方法を考えてみましょう。

いろいろなやり方が考えられるでしょうが、すぐ思いつくのは以下の3通りです。

### a）[四角の四隅の座標で判定する](https://qiita.com/noanoa07/items/0d62604c769b9810c905)

### b）[円の中心からの距離で判定する](https://qiita.com/noanoa07/items/093989a7cc9c2853c11b)

### c）[色で判定する](https://qiita.com/noanoa07/items/52eda04c7150dd3c1ea8)

これについては、長くなるので別の課題とします。
・[DXRuby：「当たり判定」を自分で作ってみよう - Qiita](https://qiita.com/noanoa07/items/b7d647bba20116c41a77)

→ 「ブロック崩し」追加課題1；衝突判定を自作してみよう - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2046177.html


## D. なるべく基本命令だけでブロック崩しを作ってみよう
RubyやDXRubyは、衝突判定だけでなく、プログラミングに便利な数々の機能を持っています。そのため、わずか100行足らずで「ブロック崩し」ができてしまいました。

もし、それらの便利な機能をなるべく使わず、基本的な機能だけを使って「ブロック崩し」を作ってみるとどうなるでしょうか？

プログラミングの本当の力が試されることになります。

例えば、以下のような基本機能だけを使うとします。
・[プログラミングの基礎力をつける：なるべく基本命令だけで作る「ブロック崩し」 on DXRuby - Qiita](https://qiita.com/noanoa07/items/f4c559d2e63507694f62)

- Rubyは、プログラミング言語として最低限の機能
- DXRubyは、ウィンドウの生成、座標(x,y)に点を描く、座標(x,y)の色を取得する、文字の表示、マウス／キー／カーソルキーの状態の取得

これについても、別の課題とします。

→ 「ブロック崩し」追加課題に向けて；コンピュータの世界の下側を見てみよう - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2048469.html

→ 「ブロック崩し」追加課題2；なるべく基本命令だけで「ブロック崩し」を作ってみよう - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2050752.html