ブラウザだけでRubyプログラミング： 1ステップずつ作っていく「ブロック崩し」（Nyle-canvas編）

（2022.6.17追記：アップグレードされた「[rbCanvas](https://rbcanvas.net)」が発表されました。
　→ [インストール不要！ブラウザだけではじめるRubyゲームプログラミング環境「rbCanvas」の紹介（DXRubyスタイル） - Qiita](https://qiita.com/noanoa07/items/bfbf3b45989c8889a868) ）

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

ブラウザだけでRubyのゲームプログラミングが始められるNyle-canvasを使って「ブロック崩し」ゲームを作っていきます。
0から少しずつ「ブロック崩し」を作っていきます。Rubyだと完成しても100数十行で「ブロック崩し」ができてしまいます。


![blocks_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c0a9c1e2-9557-b30d-5d3e-fda51cd2c06d.gif)



# 技術解説
## 使用ライブラリ
- Nyle-canvas（DXRubyスタイル）

https://spoolkitamura.github.io/nyle-canvas/

ブラウザ上で動くRubyエディタ・実行環境一体型の統合開発環境なので、Rubyのインストールは不要です。

![Nyle-canvas_editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/ce3a5a67-f290-2a06-c93e-fb730dfadda3.png)


## Nyle-canvas（DXRubyスタイル）
本テキストでは、Nyle-canvasの記述スタイルの内、DXRuby API互換の「DXRubyスタイル」を使用します。


## Nyle-canvasの使い方
下記の投稿を見てください。

- ブラウザではじめるRubyゲームプログラミング：Nyle-canvas（DXRubyスタイル）入門 - Qiita

https://qiita.com/noanoa07/items/e7ebf97edef4ae9b448a


## Nyle-canvasに必要な動作環境
- ブラウザ（Chromeなど）
- インターネット接続
- ブラウザの動くOS（Windows、macOS、Linux、Android、iPadOS、iOSなど）
- パソコン、または（外付けキーボードを接続した）タブレット、スマートフォン
（※ タッチパネル操作にも一部対応）

## Nyle-canvasのホームページ
- Nyle-canvasホームページ

https://spoolkitamura.github.io/nyle-canvas/
![Nyle-canvas_HP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/23787857-4a62-bd0d-6bd2-371d50fa4486.png)

- Nyle-canvas(DXRubyスタイル)エディタ；実際にプログラミングするエディタ画面

「[Nyle-canvasホームページ](https://spoolkitamura.github.io/nyle-canvas/)」から、「DXRubyスタイル」のリンクをクリック。
![Nyle-canvas_editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/74f7b6e0-d22c-4787-b6d2-1092e699d051.png)


- Nyle-canvasマニュアル；エディタの操作方法

https://spoolkitamura.github.io/nyle-canvas/dev2/site/manual_editor.html


## 参考サイト
「DXRubyスタイル」のオリジナルであるDXRubyのページ；

- 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の使い方を解説した記事；

- Ruby用2Dゲームライブラリ DXRuby：使い方の初歩 - Qiita
https://qiita.com/noanoa07/items/bced6519d9b53685b651


ブラウザで動く、その他のDXRuby API互換ライブラリ；

- DXOpal
https://yhara.github.io/dxopal/doc/ja/index.html

https://yhara.github.io/dxopal/index.html

- Rubyで始めるゲームプログラミング - DXOpal編 - Rubyist Magazine 0057 号
https://magazine.rubyist.net/articles/0057/0057-GameProgramingWithDXOpal.html


本テキストの元になった、DXRubyで作る「ブロック崩し」の記事；

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


## 本テキストの実行環境
- ブラウザ；
Google Chrome（バージョン 83.0.4103.61，64 ビット，macOS版）

- 実行OS；
macOS（Catalina 10.15.5）

その他、Safari/macOS，Chrome/Windows10 でも適宜動作確認


## 対応バージョン
Nyle-canvas（DXRubyスタイル）；dev2（2020/5/30リリース）


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

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


## 本テキストのソースコード
https://github.com/noanoa07/nyle-canvas-blocks


## 本テキストのライセンス
本テキスト内の解説文、Rubyソースコード、画像データはともにパブリックドメイン

（Nyle-canvasのソースコードは MITライセンス）



# プログラム解説
## 1． Nyle-canvasの使い方（概略）
Nyle-canvasの使い方については、下記の投稿を見てください。

- ブラウザではじめるRubyゲームプログラミング：Nyle-canvas（DXRubyスタイル）入門 - Qiita
https://qiita.com/noanoa07/items/e7ebf97edef4ae9b448a

ここでは、最低限の説明をします。


### 1-1． Nyle-canvasエディターを開く
Nyle-canvasは、ブラウザで以下のサイトにアクセスすることで、プログラム編集画面（エディタ）が表示されます。

![Nyle-canvas_DXRuby.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/0e9a921b-b3e0-587c-1722-04e5fe47f9c6.png)
「Nyle-canvasホームページ」
https://spoolkitamura.github.io/nyle-canvas/
から、
「DXRubyスタイル」のリンクをクリック。

![Nyle-canvas_editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/74f7b6e0-d22c-4787-b6d2-1092e699d051.png)
これが、Nyle-canvasエディタ画面になります。

なお、ここではブラウザとしてGoogle Chromeを使って説明していきます。（実行環境はmacOS。）

エディタ画面にはあらかじめ基本のプログラムが表示されています。
また、画面左上には各種ボタンが並んでいます。
右から、
- `▶︎ ボタン`；プログラム実行
- `↓ ボタン`；プログラム保存（ダウンロード）
- `Ｔボタン`；フォント（文字サイズ）設定
- `？ボタン`；ヘルプ（リファレンス）画面へ

#### ・プログラムの新規作成
ブラウザのNyle-canvas **エディタ画面で** 「再読み込み」をすると、最初の状態に戻ります。

「再読み込み」をする方法：

- ブラウザ上部の`「↻」ボタン`を押す
- `メニュー`＞`ファイル`＞`表示`＞`ページを再読み込み` を選択
- ショートカット；（macOS）`Command` + `R`、（Windows）`Ctrl` + `R`


### 1-2． プログラムの実行・再実行
プログラムは**保存操作なし**で、`▶︎ボタン`を押すだけで**即実行**されます。


```ruby
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

Window.loop do
  # 画面描画用のコード (your draw code here)
  
end
```

![rb_dx00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e79cc9e5-4572-0f26-441b-eff4ef9a2b30.png)

ブラウザの新しいタブが開き、黒い四角形の基本のウィンドウが表示されます。

座標は、左上が原点（x = 0, y = 0）、横（x）は右方向に増加、縦（y）は下方向に増加です。

`Window.loop do 〜 end`の間に書いたコードは、1秒間に60回繰り返し実行されます。

→ DXRubyリファレンス：チュートリアル 1. 基本の形
http://mirichi.github.io/dxruby-doc/tutorial/basic.html


#### ・再実行
**実行画面で**「再読み込み」をすることで、プログラムの再実行ができます。

「再読み込み」をする方法：

- ブラウザ上部の`「↻」ボタン`を押す
- `メニュー`＞`ファイル`＞`表示`＞`ページを再読み込み` を選択
- ショートカット；（macOS）`Command` + `R`、（Windows）`Ctrl` + `R`


#### ・実行画面を閉じる
実行画面のタブを閉じます。画面の上の`「×」ボタン`を押します。

- ショートカット；（macOS）`Command` + `W`、（Windows）`Ctrl` + `W`


### 1-3． プログラムの保存（ダウンロード）
`↓ボタン`を押すと、プログラムがダウンロードされます。ダウンロード先は、ブラウザの設定によりますが、「ダウンロード」フォルダになることが多いようです。


### 1-4． プログラムの読み込み
Nyle-canvasのプログラムファイル（`HTMLファイル`）をブラウザの`Nyle-canvasエディタ画面`にドラッグ＆ドロップします。

![file_drop_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/f8a2f295-6cb2-6c74-f852-cf6b240deb98.gif)


### 1-5． 画像ファイルの読み込み
Nyle-Canvasでは、画像ファイルもプログラムと合わせて一体で保存・管理します。

使いたい画像ファイルは、エディタ画面に直接`ドラッグ＆ドロップ`することで、Nyle-canvas内にコピーされ、エディタ画面下側に画像ファイルの一覧として表示されるようになります。
（※大文字が小文字になる場合があります。）

![image_drop_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/1fbce88f-dd5f-0427-7ab0-43257ed99fc7.gif)

プログラムから画像ファイルを読み込んで使うには、`Image.load(画像ファイル名)`を使います。
`画像ファイル名`の前に場所を示す**パス名などは不要**です。

読み込んだ画像は、`Imageクラス`になります。


### 1-6． コンソールの開き方
実行時の`エラーメッセージ`や`puts`などの結果は、ブラウザの`コンソール`に出力されます。

![error_console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/bff03895-34c6-4291-ea9c-663180b3bed8.png)

Chromeでの開き方；（**実行画面で**）

#### a) macOS、Windows 共通
- `F12`（あるいは `fn` + `F12`）キーを押す
- （画面上の任意の場所で）；`右クリック`（2本指クリックなど）＞`検証`＞開いたデベロッパーツールの中の`「Console」`を選択

#### b) macOS
- `メニュー`＞`表示`＞`開発/管理`＞`Javascriptコンソール` を選択
- ショートカット；`Command` + `Option` + `J`

#### c) Windows
- `メニュー`＞ `その他のツール`＞`デベロッパーツール`＞ 開いたデベロッパーツールの中の`「Console」`を選択
- ショートカット；`Ctrl` + `Shift` + `J`


### 1-7． ヘルプ（リファレンス）
Nyle-canvasエディタ画面左上の`「?」ボタン`を押すとヘルプ（リファレンス）画面が開きます。

→ \[Nyle-canvas]  APIリファレンス (DXRubyスタイル)
https://spoolkitamura.github.io/nyle-canvas/dev2/site/_man_api_dx/index.html

![Nyle-canvas_help.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/804491ba-c97d-a04a-d385-9db3deb1f96e.png)

Nyle-canvasのAPIが簡潔にまとめられているので、困ったときにはどんどん活用してください。


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

#### ※`.htmlファイル`と`.rbファイル`について
Nyle-canvasで実行するプログラムは、`.htmlファイル`です。（サンプルプログラムは `src/block_htmlフォルダ`内に入っています。）

ただし、以下の説明では Rubyのプログラム部分だけを載せていきます。（`src/block_rubyフォルダ`内に同名の`.rbファイル`が入っています。）


### 2-1． 壁を出す（左側）（rb_block01.html）
まず、左側の縦の壁を作ります（厚み20）。

左上隅を`(0, 0)`にして、横は(厚みの)20、縦は（ウィンドウの縦幅と同じ）480の白い長方形にします。
そのため、右下隅は`(20, 480)`になります

プログラムでは、`Window.draw_box_fill(左上x, 左上y, 右下x, 右下y, 色)`を使います。

これを`Window.loop do 〜 end`の中に書いて、毎回描画させます。


```rb_block01.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

Window.loop do
  Window.draw_box_fill(0, 0, 20, 480, C_WHITE)    # ◆追加
end
```

![rb_block01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/7ad8920e-c34a-db2e-03b4-1dcedd9b7826.gif)


### 2-2． 壁を出す（右側も）(rb_block02.html）
次に、右側の縦の壁を作ります。

左上隅の`x`はウィンドウ幅640から壁の厚み20を引いた`640 - 20 = 620`、`y`は`0`になります。

右下隅はウィンドウの右下隅と同じ`(640, 480)`です。


```rb_block02.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

Window.loop do
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)   # ◇変更（文字揃え）
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)   # ◆追加
end
```

![rb_block02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/1453c1ce-036b-3af2-c8ac-a5cbd72dc7e6.gif)


### 2-3． 壁を出す（上側も）(rb_block03.html）
上側の横の壁を作ります（厚み20）。

左上隅は`(0, 0)`、右下隅の`x`はウィンドウ幅と同じ`640`、`y`は壁の厚みと同じ`20`になります。


```rb_block03.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

Window.loop do
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)   # ◆追加
end
```

![rb_block03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/1ba1b688-9e51-1f8b-a0e6-b5e13c6d9061.gif)


### 2-4． バーを出す（rb_block04.html）
ボールを打ち返すバーとして、横100、縦20の水色の長方形の画像イメージ（`src/image/bar.png`）を用意します。

![bar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/8bd293ed-edb8-08de-697a-904d0860458b.png)

まず、`bar.png`ファイルをエディタ画面に直接ドラッグ＆ドロップします。これにより、Nyle-canvas内にコピーされ、エディタ画面下側の画像ファイル一覧に表示されるようになります。
![rb_block04_editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/74312792-ecc4-9430-e47b-af2251dfd568.png)

次に、 `Image.load("bar.png")`で画像ファイルを読み込みます。（パス名は不要です。）

バーの縦位置`y`は、ウィンドウの一番下`480`に合わせるため、`480 - バーの縦幅`にします。バーの横位置`x`は、0にします。

バーを表示させるには、`Window.loop do 〜 end`の中で`Window.draw(x位置, y位置, イメージ)`を使います。


```rb_block04.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")                     # ◆追加
bar_x = 0                                           # ◆追加
bar_y = 480 - img_bar.height                        # ◆追加

Window.loop do
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)                # ◆追加
end
```

![rb_block04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/d4ff7f9b-17fd-e5a2-dc57-8ba4bb717a8c.gif)


### 2-5． バーを矢印キーで動かす(rb_block05.html）
キーボードの左右矢印キー（`←` `→`）で、バーが左右（`x方向`）に動くようにします。

`Input.x`で左右の矢印キーの押された状態を取得し、その値（`-1`, `0`, `1`）をバーの`x位置`に足すことで、バーを動かします。


```rb_block05.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

Window.loop do
  bar_x = bar_x + Input.x             # ◆追加

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
end
```

![rb_block05_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/9acab4f8-2ee8-42d4-d018-083b1088e180.gif)


### 2-6． バーを矢印キーで動かす：別の書き方(rb_block06.html）

`bar_x = bar_x + Input.x`を別の書き方である、

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


```rb_block06.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

Window.loop do
  bar_x += Input.x            # ◇変更（書き方を変える）

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
end
```


### 2-7． バーの動きを素早く(rb_block07.html）
バーの動きを素早くしてみます。

`Input.x`は、`-1`, `0`, `1` の値しか返さないので、4倍して値を大きくして、バーの`x位置`に足すことにします。


```rb_block07.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

Window.loop do
  bar_x += Input.x * 4        # ◇変更（反応を速く）

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
end
```

![rb_block07_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/52dd25b0-5271-0305-db02-8a09ae208dce.gif)


### 2-8． バーをマウスで動かす(rb_block08.html）
マウスの動きに追従して、バーが左右（`x方向`）に動くようにします。

`Input.mouse_x`でマウスの`x位置`を取得し、その値をバーの`x位置`に代入することで、バーを動かします。

※ `バー`は、`左右キー`で動かしても、`マウス`で動かしても構いませんが、これ以降は`マウス`を使った例で示します。


```rb_block08.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合    # ◇変更（コメントアウト）
  bar_x = Input.mouse_x       # マウスの場合      # ◆追加

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
end
```

![rb_block08_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e0dcd0ce-344c-bb99-f302-000cf90c1160.gif)


### 2-9． バーがはみ出さないように(rb_block09.html）
バーが左右の壁をはみ出さないようにします。

バーの`x位置`は左端なので、最小値は、壁の厚みの`20`です。

一方、右端は`x位置 + バーの横幅img_bar.width`なので、最大値は、`ウィンドウの横幅640 - 壁の厚み20 - バーの横幅img_bar.width`になります。

以上を、`if 〜 elsif 〜 end`に書いていきます。


```rb_block09.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20                              # ◆追加
    bar_x = 20                               # ◆追加
  elsif bar_x > 640 - 20 - img_bar.width     # ◆追加
    bar_x = 640 - 20 - img_bar.width         # ◆追加
  end                                        # ◆追加

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
end
```

![rb_block09_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/7e2e6b75-4662-00d7-53a0-24acb81877da.gif)


### 2-10． ボールを出す(rb_block10.html）
ボールとして、横20、縦20の赤色の円の画像イメージ（`src/image/ball.png`）を用意します。

![ball.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/dc823211-766a-43b5-4933-a007898d5070.png)

「2-4．バーを出す」と同じように、`ball.png`ファイルをエディタ画面にドラッグ＆ドロップして、Nyle-canvasに登録し、`Image.load("ball.png")`で読み込みます。

#### 註）画像の透明化について
2020/5/30リリースの`dev2`では、`Image.load`時に、画像の白色を自動的に透明にするようになっています。そのため、白地に赤色のボールが描かれている`ball.png`は、背景が自動的に透明になっています。

初期位置はとりあえず、x位置を`ball_x = 300`、y位置を`ball_y = 400` とします。

あとは、`Window.draw`で描画します。


```rb_block10.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")  # ◆追加
ball_x = 300                       # ◆追加
ball_y = 400                       # ◆追加

Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)       # ◆追加
end
```

![rb_block10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/b10523cb-7ff1-30f6-2e6e-0bb17d68a947.gif)


### 2-11． ボールを動かす（横方向）(rb_block11.html）
ボールを横方向（`x方向`）に動かします。（`x`は右がプラス方向）

x方向のスピードを`dx`として、ボールのx位置`ball_x`に、loopで回ってくる（1/60秒）毎に`dx`を足していきます（`ball_x += dx`）。


```rb_block11.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     = 2                    # ◆追加


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx                # ◆追加

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block11_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/5f43b8ac-59f4-8975-a549-668debf1c8d3.gif)


### 2-12． ボールを動かす（縦方向）(rb_block12.html）
今度は縦方向（`y方向`）に動かします。（`y`は下がプラス方向）

いったん横方向に動かすのはやめて（`#ball_x += dx`でコメントアウト）、y方向のスピードを`dy`として、loopで回ってくる毎に`dy`を足していきます（`ball_y += dy`）。


```rb_block12.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2       # ◇変更（文字揃え）
dy     =  -2       # ◆追加


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  #ball_x += dx                 # ◇変更（コメントアウト）
  ball_y += dy                  # ◆追加

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block12_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/6537ba5b-50a0-005b-9d5f-aebecc94c0b5.gif)


### 2-13． ボールを動かす（縦横方向）(rb_block13.html）
`x方向`の動きも再開させる（`ball_x += dx`とコメントアウトをはずす）と、ボールは斜めに動いていきます。


```rb_block13.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx                 # ◇変更（コメントアウトをはずす）
  ball_y += dy

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block13_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/3c4aa6dc-f4f4-af1d-d639-2dcacb04c2b7.gif)


### 2-14． ボールが跳ね返る（横方向）(rb_block14.html）
ボールを跳ね返らせます。まずは、横方向（`x方向`）だけ動かします（`#ball_y += dy` でコメントアウト）。

左壁にぶつかったとは、`ボールのx位置`（`ball_x`）が左壁の厚みの`20`より小さくなった時です。

一方、右壁にぶつかったとは、`ウィンドウの横幅640 - 右壁の厚み20 = 620` より大きくなった時でしょうか？

跳ね返るとは、x方向のスピード`dx`が反対向きになることなので、`dx = -dx`と書けます。

以上を、`if 〜 end`に書いていきます。


```rb_block14.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
img_ball.set_color_key(C_WHITE)
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  #ball_y += dy                     # ◇変更（コメントアウト）

  if ball_x < 20 || ball_x > 620    # ◆追加
    dx = -dx                        # ◆追加
  end                               # ◆追加
  include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  #ball_y += dy                     # ◇変更（コメントアウト）

  if ball_x < 20 || ball_x > 620    # ◆追加
    dx = -dx                        # ◆追加
  end                               # ◆追加
  
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block14_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c5c421fa-09ac-a6b0-3d3f-d05d625f6549.gif)
右側は壁の中まで入ってしまいました。
![rb_block14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/57e45daa-4292-3fb9-826e-c2d9aa6c4dcc.gif)


### 2-15． ボールが跳ね返る（横方向）：修正(rb_block15.html）
`ボールのx位置`（`ball_x`）はボールの左端なので、右端は`ボールの幅`（`ball_width`）を足した`ball_x + ball_width`になります。

"右壁にぶつかった" とは、この値が`ウィンドウの横幅640 - 右壁の厚み20 = 620` より大きくなった時にしなければなりません。

`(ball_x + ball_width) > 620`

なお、衝突の様子をゆっくり観察するために、1秒当たりの描画回数の設定（初期値：60）を半分の30にしています。

`Window.fps = 30`


```rb_block15.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width              # ◆追加

# 1秒当たりの描画回数の設定（初期値：60） # ◆追加
Window.fps = 30                           # ◆追加


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  #ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620   # ◇変更
    dx = -dx
  end
  
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block15_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/dca4bad1-ac64-cf56-dd21-8789b654f195.gif)
これで良さそうですが、よ〜く見ると一瞬、壁にボールがめり込んでいます（左右の壁とも）。
![rb_block15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/264407cd-4293-b444-1dfc-2f19b0d907d8.gif)


### 2-16． ボールが跳ね返る（横方向）：修正2(rb_block16.html）
これまでは、壁にぶつかったら、ボールの`x方向の速度`（`dx = -dx`）を逆向きにしただけでした。

これだと跳ね返りはしますが、ボールの位置（`ball_x`）は変えていないので、ボールは壁にめり込んだままです。

そこで、ボールの位置（`ball_x`）も、動いてきた分（`+dx`）を逆に戻すことにします（`ball_x -= dx`）。


```rb_block16.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 0
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width

# 1秒当たりの描画回数の設定（初期値：60）
Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  #ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx                                  # ◆追加
    dx = -dx
  end
  
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block16_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/28e4db88-9006-9b24-b555-3ee0379502c4.gif)
こんどこそ良さそうです。
![rb_block16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/88798972-df36-9adf-a448-5359b001ae40.gif)


### 2-17． ボールが跳ね返る（縦方向）(rb_block17.html）
今度はボールを縦方向（`y方向`）だけ動かして、上壁で跳ね返るようにします。

上壁にぶつかったとは、ボールの`y位置`（`ball_y`）が上壁の厚み`20`より小さくなった時です。

なお、1秒当たりの描画回数は元に戻して（コメントアウト）、バーの`x位置`の初期値を中央寄りに変えています。


```rb_block17.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250                        # ◇変更（数値変更）
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height       # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30                    # ◇変更（コメントアウト）


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  #ball_x += dx                     # ◇変更（コメントアウト）
  ball_y += dy                      # ◇変更（コメントアウトをはずす）

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20                   # ◆追加
    ball_y -= dy                   # ◆追加
    dy = -dy                       # ◆追加
  end                              # ◆追加

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block17_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/bba399ba-4ffa-a144-951a-c26b09669ed2.gif)
まだ、バーでは跳ね返りません。


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


```rb_block18.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx                   # ◇変更（コメントアウトをはずす）
  ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end

  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block18_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/5dcb9f57-416d-dab2-c9d4-1ea696ee5d89.gif)


### 2-19． ボールが跳ね返る（バーと）(rb_block19.html）
バーでも跳ね返るようにします。

ボールがバーにぶつかった時の条件は；
#### ○`y座標`
- `ボールの下` > `バーの上`

`（ball_y + ball_height） > (480 - bar_height)`

#### ○`x座標`
- `ボールの右` > `バーの左`

`(ball_x + ball_width)  > bar_x`

- `ボールの左` < `バーの右`

`ball_x  < (bar_x + bar_width)`

以上の条件を同時に満たす時です（`&&`）。


```rb_block19.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width                 # ◆追加
bar_height = img_bar.height                # ◆追加

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  if (ball_y + ball_height) > (480 - bar_height)  &&  # ◆追加
     (ball_x + ball_width)  > bar_x               &&  # ◆追加
     ball_x                 < (bar_x + bar_width)     # ◆追加
                                                      # ◆追加
    ball_y -= dy                                      # ◆追加
    dy = -dy                                          # ◆追加
  end                                                 # ◆追加


  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block19_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e91b6320-3d82-37c5-1867-1f90300ebfbd.gif)
これで良さそうですが、バーを動かしながら横から当たった時の跳ね返りが変です。
![rb_block19_a_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/cc16bc2d-f337-14b6-d074-85471868804e.gif)
![rb_block19_a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/52cc1c07-603d-6abf-9f9b-22e7457f8ac9.gif)


### 2-20． ボールが跳ね返る（バーと）：修正(rb_block20.html）
一旦ボールがバーに入り込みすぎてしまうと、跳ね返り処理をしてもまだバーの中なので、`dy`がプラスとマイナスを繰り返すばかりで、バーから出られなくなってしまいます。

そこで、`跳ね返り処理をした時に、バーの外に出られる場合のみ`跳ね返るというように、条件を追加します。

`y方向`で、

`ボールの下` <= `バーの上よりdyの絶対値分だけ下`

`(ball_y + ball_height) <= (480 - bar_height + dy.abs)`


```rb_block20.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  if (ball_y + ball_height) >  (480 - bar_height)  &&           # ◇変更（文字位置合わせ）
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&  # ◆追加
     (ball_x + ball_width)  >  bar_x               &&           # ◇変更（文字位置合わせ）
     ball_x                 <  (bar_x + bar_width)              # ◇変更（文字位置合わせ）
    
    ball_y -= dy
    dy = -dy
  end


  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)
end
```

![rb_block20_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/727b7a6b-753c-e5bd-553f-c2e20fcc263d.gif)
今度は、いいようです。
![rb_block20.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/53118810-ea56-1b0a-cff2-1af5afed5bbb.gif)


### 2-21． ブロックを出す（1個）(rb_block21.html）
ここからは、ブロックを作っていきます。まずは1個。

ブロックとして、横58、縦18の大きさの緑の長方形の画像イメージ（`src/image/block.png`）を用意します。

![block.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/4ee25594-fa34-a9a9-a1e2-ed58b808d937.png)

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

この`block.png`ファイルをエディタ画面にドラッグ＆ドロップして、Nyle-canvas内に登録します。

次に、 `Image.load("block.png")`で画像ファイルを読み込みます。（パス名は不要です。）

最初のブロックを`block00`として、位置は左上の壁の内側（`x = 20`, `y = 20`）から横、縦とも`1`だけ隙間を空けて、`block00_x = 21`、`block00_y = 21`に配置します。

そして、`Window.draw(block00_x, block00_y, img_block)`で描画します。


```rb_block21.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

img_block = Image.load("block.png")                # ◆追加
block_widh = img_block.width                       # ◆追加
block_height = img_block.height                    # ◆追加

block00_x = 21                                     # ◆追加
block00_y = 21                                     # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  Window.draw(block00_x, block00_y, img_block)          # ◆追加
end
```

![rb_block21.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/21e89a77-50d9-2b3f-4c77-9c5aff7045a0.gif)


### 2-22． ブロックを出す（2個）(rb_block22.html）
2個目のブロック（`block01`）は、同じイメージを使って、`ブロックの横幅（block_widh）+ 隙間（2）` だけ右にずらした位置に置きます。


```rb_block22.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

img_block = Image.load("block.png")
block_widh = img_block.width
block_height = img_block.height

block00_x = 21
block00_y = 21

block01_x = 21 + block_widh + 2                    # ◆追加
block01_y = 21                                     # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  Window.draw(block00_x, block00_y, img_block)
  Window.draw(block01_x, block01_y, img_block)          # ◆追加
end
```

![rb_block22.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/0a8f59be-3c18-d62d-da61-35ce01f4c68a.gif)


### 2-23． ブロックを出す（3個）(rb_block23.html）
同じく3個目のブロック（block02）を置きます。x位置は、ブロックと隙間を見込んで`block_widh + 2`ずつずらしていきます。


```rb_block23.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

img_block = Image.load("block.png")
block_widh = img_block.width
block_height = img_block.height

block00_x = 21
block00_y = 21

block01_x = 21 + block_widh + 2
block01_y = 21

block02_x = 21 + (block_widh + 2) * 2              # ◆追加
block02_y = 21                                     # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  Window.draw(block00_x, block00_y, img_block)
  Window.draw(block01_x, block01_y, img_block)
  Window.draw(block02_x, block02_y, img_block)          # ◆追加
end
```

![rb_block23.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/35df934a-2ff1-a11d-60be-318e0ec0da2b.gif)


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


```rb_block24.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

img_block = Image.load("block.png")
block_widh = img_block.width
block_height = img_block.height

block00_x = 21
block00_y = 21

block01_x = 21 + block_widh + 2
block01_y = 21

block02_x = 21 + (block_widh + 2) * 2
block02_y = 21

block03_x = 21 + (block_widh + 2) * 3              # ◆追加
block03_y = 21                                     # ◆追加

block04_x = 21 + (block_widh + 2) * 4              # ◆追加
block04_y = 21                                     # ◆追加

block05_x = 21 + (block_widh + 2) * 5              # ◆追加
block05_y = 21                                     # ◆追加

block06_x = 21 + (block_widh + 2) * 6              # ◆追加
block06_y = 21                                     # ◆追加

block07_x = 21 + (block_widh + 2) * 7              # ◆追加
block07_y = 21                                     # ◆追加

block08_x = 21 + (block_widh + 2) * 8              # ◆追加
block08_y = 21                                     # ◆追加

block09_x = 21 + (block_widh + 2) * 9              # ◆追加
block09_y = 21                                     # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


Window.loop do
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  ball_x += dx
  ball_y += dy

  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  Window.draw(block00_x, block00_y, img_block)
  Window.draw(block01_x, block01_y, img_block)
  Window.draw(block02_x, block02_y, img_block)
  Window.draw(block03_x, block03_y, img_block)          # ◆追加
  Window.draw(block04_x, block04_y, img_block)          # ◆追加
  Window.draw(block05_x, block05_y, img_block)          # ◆追加
  Window.draw(block06_x, block06_y, img_block)          # ◆追加
  Window.draw(block07_x, block07_y, img_block)          # ◆追加
  Window.draw(block08_x, block08_y, img_block)          # ◆追加
  Window.draw(block09_x, block09_y, img_block)          # ◆追加
end
```

![rb_block24.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/5f847954-5d00-7b33-f1a1-05becdb4fa58.gif)


### 2-25． ブロックをまとめて作る（`Itemクラス`）(rb_block25.html）
ブロックを作る／描画するプログラムが10回も繰り返したので、まとめて作ることします。

以下のような手順で作っていきます。

#### 1) `Itemクラス`というクラスを作る
ブロックを扱うのに、以下のような属性をまとめて扱えると便利です。

- x位置
- y位置
- イメージ
- イメージの幅
- イメージの高さ

それを踏まえて、`Itemクラス`というクラスを作ることにします。


```ruby
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height
end       
```

これで、`Itemクラス`（のインスタンス）は、`x位置`、`y位置`、`イメージ`、`幅`、`高さ`をもつようになります。


#### 2) ブロックのイメージを用意する

`img_block = Image.load("block.png")`


#### 3) `Itemクラス`でブロックを作る

`Item.new(x位置, y位置, img_block)`


#### 4) 複数のブロック（ブロック群）を作るために、配列`blocks`を用意する
`blocks = []`で、空の配列`blocks`を作ります。


#### 5) ブロックを1つずつ作って、配列`blocks`に追加していく
配列に追加していく`<<`メソッドを使って、ブロックを1つ作っては配列`blocks`に追加する操作を繰り返します。

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

```ruby
10.times do |x|
  blocks << Item.new(21 + (img_block.width + 2) * x, 21, img_block)
```


#### 6) ブロック群の描画もまとめる
ブロック群`blocks`は配列なので、繰り返し操作する `配列.each do |配列要素| 〜 end` が使えます。

```ruby
blocks.each do |block|
  Window.draw(block.x, block.y, block.image)
end
```

以上で、プログラムがだいぶすっきりしました。（コメントも追加してあります。）


```rb_block25.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20                            # ◆追加（コメント）

# ブロックはItemクラスにする                          # ◆追加（コメント）
class Item                                        # ◆追加
  def initialize(x, y, image)                     # ◆追加
    @x = x                                        # ◆追加
    @y = y                                        # ◆追加
    @image  = image                               # ◆追加
    @width  = image.width                         # ◆追加
    @height = image.height                        # ◆追加
  end                                             # ◆追加
  attr_accessor :x, :y, :image, :width, :height   # ◆追加
end                                               # ◆追加

# バーの準備                                        # ◆追加（コメント）
img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

# ボールの準備                                       # ◆追加（コメント）
img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

# ブロックの準備                                      # ◆追加（コメント）
img_block = Image.load("block.png")

# ブロック群の初期化                                   # ◆追加（コメント）
blocks = []                                         # ◆追加
10.times do |x|                                     # ◆追加
  blocks << Item.new(21 + (img_block.width + 2) * x, 21, img_block)   # ◆追加
end                                                 # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ                                        # ◆追加（コメント）
Window.loop do
  # バーを動かす                                      # ◆追加（コメント）
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  # ボールを動かす                                     # ◆追加（コメント）
  ball_x += dx
  ball_y += dy

  # 壁に当たったら、跳ね返る（x方向）                     # ◆追加（コメント）
  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  # 壁に当たったら、跳ね返る(y方向)                       # ◆追加（コメント）
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  # バーとの衝突判定                                    # ◆追加（コメント）
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  # 画面描画                                           # ◆追加（コメント）
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  blocks.each do |block|                             # ◆追加
    Window.draw(block.x, block.y, block.image)       # ◆追加
  end                                                # ◆追加
end
```

![rb_block25.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/28b524f1-758b-def9-fca6-52c3640e4e5b.gif)


### 2-26． ブロックを出す（2段目も作る）(rb_block26.html）
2段目のブロックも作っていきます。

2段目は、`yの位置`を`ブロックの高さ（img_block.height） + 隙間（2）`だけ大きくします。

1段目と同じく10.times do 〜 endを使って書きます。


```rb_block26.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height
end

# バーの準備
img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

# ボールの準備
img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  blocks << Item.new(21 + (img_block.width + 2) * x, 21, img_block)
end

10.times do |x|                                     # ◆追加
  blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2), img_block)   # ◆追加
end                                                 # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  # ボールを動かす
  ball_x += dx
  ball_y += dy

  # 壁に当たったら、跳ね返る（x方向）
  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  # 壁に当たったら、跳ね返る(y方向)
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  # バーとの衝突判定
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```

![rb_block26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/31269875-2362-8b95-f149-57304b316110.gif)


### 2-27． ブロックを出す（5段目まで作る）(rb_block27.html）
5段目まで作りました。


```rb_block27.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height
end

# バーの準備
img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

# ボールの準備
img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  blocks << Item.new(21 + (img_block.width + 2) * x, 21, img_block)
end

10.times do |x|
  blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2), img_block)
end

10.times do |x|                                     # ◆追加
  blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * 2, img_block)   # ◆追加
end                                                 # ◆追加

10.times do |x|                                     # ◆追加
  blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * 3, img_block)   # ◆追加
end                                                 # ◆追加

10.times do |x|                                     # ◆追加
  blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * 4, img_block)   # ◆追加
end                                                 # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  # ボールを動かす
  ball_x += dx
  ball_y += dy

  # 壁に当たったら、跳ね返る（x方向）
  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  # 壁に当たったら、跳ね返る(y方向)
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  # バーとの衝突判定
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```

![rb_block27.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/3e4a52c8-a9ed-63f5-d008-62a5f8469180.gif)


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

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


```rb_block28.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height
end

# バーの準備
img_bar = Image.load("bar.png")
bar_x = 250
bar_y = 480 - img_bar.height
bar_width  = img_bar.width
bar_height = img_bar.height

# ボールの準備
img_ball = Image.load("ball.png")
ball_x = 300
ball_y = 400
dx     =   2
dy     =  -2
ball_width  = img_ball.width
ball_height = img_ball.height

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|                                  # ◆追加
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)  # ◆追加
  end                                             # ◆追加
end

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar_x += Input.x * 4       # 左右キーの場合
  bar_x = Input.mouse_x       # マウスの場合
  if bar_x < 20
    bar_x = 20
  elsif bar_x > 640 - 20 - img_bar.width
    bar_x = 640 - 20 - img_bar.width
  end

  # ボールを動かす
  ball_x += dx
  ball_y += dy

  # 壁に当たったら、跳ね返る（x方向）
  if ball_x < 20 || (ball_x + ball_width) > 620
    ball_x -= dx
    dx = -dx
  end
  
  # 壁に当たったら、跳ね返る(y方向)
  if ball_y < 20
    ball_y -= dy
    dy = -dy
  end
  
  # バーとの衝突判定
  if (ball_y + ball_height) >  (480 - bar_height)  &&
     (ball_y + ball_height) <= (480 - bar_height + dy.abs)  &&
     (ball_x + ball_width)  >  bar_x               &&
     ball_x                 <  (bar_x + bar_width)
    
    ball_y -= dy
    dy = -dy
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar_x, bar_y, img_bar)
  Window.draw(ball_x, ball_y, img_ball)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```


### 2-29． ボール、バーも`Itemクラス`にする(rb_block29.html）
考えてみると、ボールとバーの属性も`Itemクラス`とほとんど同じなので、`Itemクラス`にすることにします。

これでまた、プログラムが見やすくなりました。


```rb_block29.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする         # ◇変更（ボール、バーもItemクラスに作り替え）
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height
end

# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)  # ◇変更（Itemクラスに作り替え）

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)                 # ◇変更（Itemクラスに作り替え）
dx =  2   # ボールのスピード（x方向）                   # ◇変更（文字揃え、コメント追加）
dy = -2   # ボールのスピード（y方向）                   # ◇変更（文字揃え、コメント追加）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合   # ◇変更（bar.x に）
  bar.x = Input.mouse_x       # マウスの場合     # ◇変更（bar.x に）
  if bar.x < 20                                # ◇変更（bar.x に）
    bar.x = 20                                 # ◇変更（bar.x に）
  elsif bar.x > 640 - 20 - bar.width           # ◇変更（bar.x、bar.width に）
    bar.x = 640 - 20 - bar.width               # ◇変更（bar.x、bar.width に）
  end

  # ボールを動かす
  ball.x += dx                                 # ◇変更（ball.x に）
  ball.y += dy                                 # ◇変更（ball.y に）

  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620  # ◇変更（ball.x、ball.width に）
    ball.x -= dx                               # ◇変更（ball.x に）
    dx = -dx
  end
  
  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20                               # ◇変更（ball.y に）
    ball.y -= dy                               # ◇変更（ball.y に）
    dy = -dy
  end
  
  # バーとの衝突判定
  if (ball.y + ball.height) >  (480 - bar.height)  &&                # ◇変更（ball.y、ball.height、bar.height に）
     (ball.y + ball.height) <= (480 - bar.height + dy.abs)  &&       # ◇変更（ball.y、ball.height、bar.height に）
     (ball.x + ball.width)  >  bar.x               &&                # ◇変更（ball.x、ball.width、bar.x に）
     ball.x                 <  (bar.x + bar.width)                   # ◇変更（ball.x、bar.x、bar.width に）
    
    ball.y -= dy                               # ◇変更（ball.y に）
    dy = -dy
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)        # ◇変更（bar.x、bar.y、bar.image に）
  Window.draw(ball.x, ball.y, ball.image)     # ◇変更（ball.x、ball.y、ball.image に）

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```


### 2-30． 衝突判定`collision?`を作る(rb_block30.html）
今後、バーだけでなく、ブロックとの衝突判定を何回も行うので、衝突判定`collision?`を作っておきます。ここでは、四角形同士で考えることにします。

`item_a` と `item_b` という2つの長方形を考えると；

- `item_a`の座標；左上（`a_x0`, `a_y0`）、右下（`a_x1`, `a_y1`）

- `item_b`の座標；左上（`b_x0`, `b_y0`）、右下（`b_x1`, `b_y1`）

`item_a`のx座標は、`a_x0〜a_x1`、y座標は`a_y0〜a_y1`

`item_b`のx座標は、`b_x0〜b_x1`、y座標は`b_y0〜b_y1`

それぞれの座標（x, y）を考えて、2つが衝突している（ぶつかっている）条件は、以下のようになります。

```
a_x0 < b_x1 かつ
a_x1 > b_x0 かつ

a_y0 < b_y1 かつ
a_y1 > b_y0
```

これをコーディングすると以下のようになります。（`item_a`、`item_b`は、`Itemクラス`とする）

```ruby
def collision?(item_a, item_b)
  a_x0 = item_a.x
  a_x1 = item_a.x + item_a.width
  a_y0 = item_a.y
  a_y1 = item_a.y + item_a.height
  
  b_x0 = item_b.x
  b_x1 = item_b.x + item_b.width
  b_y0 = item_b.y
  b_y1 = item_b.y + item_b.height
  
  if a_x0 < b_x1 &&
     a_x1 > b_x0 &&
     a_y0 < b_y1 &&
     a_y1 > b_y0 
    
    true
  end
end 
```

`collision?`は、衝突していると`true`を返します。

（その他の衝突判定の考え方（円、色）については、以下を参照；

→ ・DXRuby：「当たり判定」を自分で作ってみよう - Qiita
https://qiita.com/noanoa07/items/b7d647bba20116c41a77 ）

また、跳ね返る方向（`x方向`、`y方向`）を考える必要があるため、ボールの移動は`x方向`、`y方向`に分けて行い、それぞれで衝突判定をするようにします。


```rb_block30.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height
end

# 衝突判定                           # ◆追加
def collision?(item_a, item_b)      # ◆追加
  a_x0 = item_a.x                   # ◆追加
  a_x1 = item_a.x + item_a.width    # ◆追加
  a_y0 = item_a.y                   # ◆追加
  a_y1 = item_a.y + item_a.height   # ◆追加
                                    # ◆追加
  b_x0 = item_b.x                   # ◆追加
  b_x1 = item_b.x + item_b.width    # ◆追加
  b_y0 = item_b.y                   # ◆追加
  b_y1 = item_b.y + item_b.height   # ◆追加
                                    # ◆追加
  if a_x0 < b_x1 &&                 # ◆追加
     a_x1 > b_x0 &&                 # ◆追加
     a_y0 < b_y1 &&                 # ◆追加
     a_y1 > b_y0                    # ◆追加 
                                    # ◆追加
    true                            # ◆追加
  end                               # ◆追加
end                                 # ◆追加

# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)
dx =  2   # ボールのスピード（x方向）
dy = -2   # ボールのスピード（y方向）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合
  bar.x = Input.mouse_x       # マウスの場合
  if bar.x < 20
    bar.x = 20
  elsif bar.x > 640 - 20 - bar.width
    bar.x = 640 - 20 - bar.width
  end


  # ボールをy方向に動かす           # ◇変更（y方向だけに）
  ball.y += dy                   # ◇変更（y方向だけに）

  # バーとの衝突判定
  if collision?(ball, bar)       # ◇変更（書き直し）
    if ball.y + ball.height  <=  480 - bar.height + dy.abs  # ◇変更（書き直し）
      ball.y -= dy               # ◇変更（書き直し）
      dy = -dy                   # ◇変更（書き直し）
    end                          # ◇変更（書き直し）
  end                            # ◇変更（書き直し）

  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20
    ball.y -= dy
    dy = -dy
  end


  # ボールをx方向に動かす           # ◇変更（x方向だけに）
  ball.x += dx                   # ◇変更（x方向だけに）

  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620
    ball.x -= dx
    dx = -dx
  end
  

  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)
  Window.draw(ball.x, ball.y, ball.image)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```

![rb_block30_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/c695e710-500a-3058-f8a4-0436975b0205.gif)


### 2-31． `collision?`を`Itemクラス`のメソッドにする(rb_block31.html）
Rubyでは、`collision?(item_a, item_b)`という書き方より、`item_a.collision?(item_b)`という書き方が多く使われます（オブジェクト指向）。

そのためには、`collision?`を`Itemクラス`のメソッドにしましょう（正確にはインスタンスメソッド）。

作り方は、以下のようにします。

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

ここで、`item_a`に相当するものは、`self`と書きます。

```ruby
class Item
  
  def collision?(item_b)
    a_x0 = self.x
    a_x1 = self.x + self.width
    a_y0 = self.y
    a_y1 = self.y + self.height
    
    b_x0 = item_b.x
    b_x1 = item_b.x + item_b.width
    b_y0 = item_b.y
    b_y1 = item_b.y + item_b.height
    
    if a_x0 < b_x1 &&
       a_x1 > b_x0 &&
       a_y0 < b_y1 && 
       a_y1 > b_y0
      
      true
    end
  end
end
```

これで、今までの`collision?(ball, bar)`という書き方から、`ball.collision?(bar)` という書き方になります。


```rb_block31.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height

  # 衝突判定                           # ◇変更（Itemクラスのメソッドに）
  def collision?(item_b)              # ◇変更（書き直し）
    a_x0 = self.x                     # ◇変更（書き直し）
    a_x1 = self.x + self.width        # ◇変更（書き直し）
    a_y0 = self.y                     # ◇変更（書き直し）
    a_y1 = self.y + self.height       # ◇変更（書き直し）
                                      # ◇変更（書き直し）
    b_x0 = item_b.x                   # ◇変更（書き直し）
    b_x1 = item_b.x + item_b.width    # ◇変更（書き直し）
    b_y0 = item_b.y                   # ◇変更（書き直し）
    b_y1 = item_b.y + item_b.height   # ◇変更（書き直し）
                                      # ◇変更（Itemクラスのメソッドに）
    if a_x0 < b_x1 &&                 # ◇変更（Itemクラスのメソッドに）
       a_x1 > b_x0 &&                 # ◇変更（Itemクラスのメソッドに）
       a_y0 < b_y1 &&                 # ◇変更（Itemクラスのメソッドに） 
       a_y1 > b_y0                    # ◇変更（Itemクラスのメソッドに）
                                      # ◇変更（Itemクラスのメソッドに）
      true                            # ◇変更（Itemクラスのメソッドに）
    end                               # ◇変更（Itemクラスのメソッドに）
  end                                 # ◇変更（Itemクラスのメソッドに）
end                                   # ◇変更（Itemクラスのメソッドに）


# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)
dx =  2   # ボールのスピード（x方向）
dy = -2   # ボールのスピード（y方向）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合
  bar.x = Input.mouse_x       # マウスの場合
  if bar.x < 20
    bar.x = 20
  elsif bar.x > 640 - 20 - bar.width
    bar.x = 640 - 20 - bar.width
  end


  # ボールをy方向に動かす
  ball.y += dy

  # バーとの衝突判定
  if ball.collision?(bar)        # ◇変更（書き直し）
    if ball.y + ball.height  <=  480 - bar.height + dy.abs
      ball.y -= dy
      dy = -dy
    end
  end

  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20
    ball.y -= dy
    dy = -dy
  end


  # ボールをx方向に動かす
  ball.x += dx

  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620
    ball.x -= dx
    dx = -dx
  end
  

  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)
  Window.draw(ball.x, ball.y, ball.image)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```


### 2-32． ブロックとの衝突判定(当たったブロックは消える)(rb_block32.html）
ブロックとの衝突判定をします。

`配列.delete_if`は、配列要素を1つずつ取り出し、条件に当てはまる場合は、配列から削除する命令です。

そのため、ブロック群の配列`blocks`から、衝突判定で`true`になったブロックを削除することができます。

```ruby
blocks.delete_if do |block|
  if ball.collision?(block)
    true
  end
end
```

これを使ったコードが以下のようになります。


```rb_block32.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height

  # 衝突判定
  def collision?(item_b)
    a_x0 = self.x
    a_x1 = self.x + self.width
    a_y0 = self.y
    a_y1 = self.y + self.height
    
    b_x0 = item_b.x
    b_x1 = item_b.x + item_b.width
    b_y0 = item_b.y
    b_y1 = item_b.y + item_b.height
    
    if a_x0 < b_x1 &&
       a_x1 > b_x0 &&
       a_y0 < b_y1 && 
       a_y1 > b_y0
      
      true
    end
  end
end


# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)
dx =  2   # ボールのスピード（x方向）
dy = -2   # ボールのスピード（y方向）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合
  bar.x = Input.mouse_x       # マウスの場合
  if bar.x < 20
    bar.x = 20
  elsif bar.x > 640 - 20 - bar.width
    bar.x = 640 - 20 - bar.width
  end


  # ボールをy方向に動かす
  ball.y += dy

  # バーとの衝突判定
  if ball.collision?(bar)
    if ball.y + ball.height  <=  480 - bar.height + dy.abs
      ball.y -= dy
      dy = -dy
    end
  end

  # ブロックとの衝突判定（y方向）         # ◆追加
  blocks.delete_if do |block|        # ◆追加
    if ball.collision?(block)        # ◆追加
      true                           # ◆追加
    end                              # ◆追加
  end                                # ◆追加

  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20
    ball.y -= dy
    dy = -dy
  end


  # ボールをx方向に動かす
  ball.x += dx

  # ブロックとの衝突判定（x方向）         # ◆追加
  blocks.delete_if do |block|        # ◆追加
    if ball.collision?(block)        # ◆追加
      true                           # ◆追加
    end                              # ◆追加
  end                                # ◆追加
  
  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620
    ball.x -= dx
    dx = -dx
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)
  Window.draw(ball.x, ball.y, ball.image)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```

![rb_block32_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/6aa5add7-911d-499d-a9ea-13e9d60b21de.gif)


### 2-33． ブロックに当たったら跳ね返る；一応完成(rb_block33.html）
ブロック当たったら跳ね返るようにします。

ブロックと衝突したら、跳ね返るコードを足すだけです。

```ruby
# ブロックとの衝突判定（y方向）
blocks.delete_if do |block|
  if ball.collision?(block)
    ball.y -= dy                      # ◆追加
    dy = -dy                          # ◆追加
    true
  end
end
```

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


```rb_block33.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height

  # 衝突判定
  def collision?(item_b)
    a_x0 = self.x
    a_x1 = self.x + self.width
    a_y0 = self.y
    a_y1 = self.y + self.height
    
    b_x0 = item_b.x
    b_x1 = item_b.x + item_b.width
    b_y0 = item_b.y
    b_y1 = item_b.y + item_b.height
    
    if a_x0 < b_x1 &&
       a_x1 > b_x0 &&
       a_y0 < b_y1 && 
       a_y1 > b_y0
      
      true
    end
  end
end


# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)
dx =  2   # ボールのスピード（x方向）
dy = -2   # ボールのスピード（y方向）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合
  bar.x = Input.mouse_x       # マウスの場合
  if bar.x < 20
    bar.x = 20
  elsif bar.x > 640 - 20 - bar.width
    bar.x = 640 - 20 - bar.width
  end


  # ボールをy方向に動かす
  ball.y += dy

  # バーとの衝突判定
  if ball.collision?(bar)
    if ball.y + ball.height  <=  480 - bar.height + dy.abs
      ball.y -= dy
      dy = -dy
    end
  end

  # ブロックとの衝突判定（y方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.y -= dy                      # ◆追加
      dy = -dy                          # ◆追加
      true
    end
  end

  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20
    ball.y -= dy
    dy = -dy
  end


  # ボールをx方向に動かす
  ball.x += dx

  # ブロックとの衝突判定（x方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.x -= dx                      # ◆追加
      dx = -dx                          # ◆追加
      true
    end
  end
  
  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620
    ball.x -= dx
    dx = -dx
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)
  Window.draw(ball.x, ball.y, ball.image)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end
end
```

![rb_block33_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/879575d9-30fe-2055-29d0-4272b4dbcb82.gif)



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

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

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


## B. 機能を拡張する
「ブロック崩し」の機能を追加して、発展させてみましょう。

### B-1． 画面に文字を表示する(rb_block34.html）
画面に文字を表示してみましょう。

まず、初期設定でフォントを準備します。

`font = Font.new(24)` 

文字の表示は以下のようにします。

`Window.draw_font(x位置, y位置, 文字列, font, {:color => 文字色)`

残りブロック数を知るには、ブロック群の配列`blocks`の要素数を調べればよいので、`blocks.size`とします。


```rb_block34.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height

  # 衝突判定
  def collision?(item_b)
    a_x0 = self.x
    a_x1 = self.x + self.width
    a_y0 = self.y
    a_y1 = self.y + self.height
    
    b_x0 = item_b.x
    b_x1 = item_b.x + item_b.width
    b_y0 = item_b.y
    b_y1 = item_b.y + item_b.height
    
    if a_x0 < b_x1 &&
       a_x1 > b_x0 &&
       a_y0 < b_y1 && 
       a_y1 > b_y0
      
      true
    end
  end
end


# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)
dx =  2   # ボールのスピード（x方向）
dy = -2   # ボールのスピード（y方向）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# フォントの準備                                         # ◆追加
font = Font.new(24)                                    # ◆追加

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合
  bar.x = Input.mouse_x       # マウスの場合
  if bar.x < 20
    bar.x = 20
  elsif bar.x > 640 - 20 - bar.width
    bar.x = 640 - 20 - bar.width
  end


  # ボールをy方向に動かす
  ball.y += dy

  # バーとの衝突判定
  if ball.collision?(bar)
    if ball.y + ball.height  <=  480 - bar.height + dy.abs
      ball.y -= dy
      dy = -dy
    end
  end

  # ブロックとの衝突判定（y方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.y -= dy
      dy = -dy
      true
    end
  end

  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20
    ball.y -= dy
    dy = -dy
  end


  # ボールをx方向に動かす
  ball.x += dx

  # ブロックとの衝突判定（x方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.x -= dx
      dx = -dx
      true
    end
  end
  
  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620
    ball.x -= dx
    dx = -dx
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)
  Window.draw(ball.x, ball.y, ball.image)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end

  # 文字の表示                                                        # ◆追加
  string = "残りブロックは #{blocks.size}個です。"                      # ◆追加
  Window.draw_font(20, 200, string, font, {:color => C_YELLOW})     # ◆追加
end
```

![rb_block34_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/f5adbfc1-becc-f85b-cf93-c56692808fbd.gif)


### B-2． ゲームオーバー画面を追加する(rb_block35.html）
ゲームオーバー画面を追加してみます。

ボールの`y位置`（`ball.y`）が、ウィンドウの縦幅`480`より大きくなったら、「ゲームオーバー画面」を表示するようにします。

ゲームオーバー画面は以下のようにして作っています。
1. ウィンドウサイズ（640, 480）と同じ大きさの白色の四角形を描く（`Window.draw_box_fill(0, 0, 640, 480, C_WHITE)`）

1. 「ゲームオーバー」という文字を表示させる（`Window.draw_font(200, 200, "ゲームオーバー", font, {:color => C_BLACK})`）

これを追加したコードです。


```rb_block35.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height

  # 衝突判定
  def collision?(item_b)
    a_x0 = self.x
    a_x1 = self.x + self.width
    a_y0 = self.y
    a_y1 = self.y + self.height
    
    b_x0 = item_b.x
    b_x1 = item_b.x + item_b.width
    b_y0 = item_b.y
    b_y1 = item_b.y + item_b.height
    
    if a_x0 < b_x1 &&
       a_x1 > b_x0 &&
       a_y0 < b_y1 && 
       a_y1 > b_y0
      
      true
    end
  end
end


# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)
dx =  2   # ボールのスピード（x方向）
dy = -2   # ボールのスピード（y方向）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# フォントの準備
font = Font.new(24)

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合
  bar.x = Input.mouse_x       # マウスの場合
  if bar.x < 20
    bar.x = 20
  elsif bar.x > 640 - 20 - bar.width
    bar.x = 640 - 20 - bar.width
  end


  # ボールをy方向に動かす
  ball.y += dy

  # バーとの衝突判定
  if ball.collision?(bar)
    if ball.y + ball.height  <=  480 - bar.height + dy.abs
      ball.y -= dy
      dy = -dy
    end
  end

  # ブロックとの衝突判定（y方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.y -= dy
      dy = -dy
      true
    end
  end

  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20
    ball.y -= dy
    dy = -dy
  end


  # ボールをx方向に動かす
  ball.x += dx

  # ブロックとの衝突判定（x方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.x -= dx
      dx = -dx
      true
    end
  end
  
  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620
    ball.x -= dx
    dx = -dx
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)
  Window.draw(ball.x, ball.y, ball.image)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end

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

  # ゲームオーバー画面                                                         # ◆追加
  if ball.y >= 480                                                          # ◆追加
    Window.draw_box_fill(0, 0, 640, 480, C_WHITE)                           # ◆追加
    Window.draw_font(200, 200, "ゲームオーバー", font, {:color => C_BLACK})   # ◆追加
  end                                                                       # ◆追加

end
```

![rb_block35_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/9faf9d32-260d-7121-3198-c6b5d7233534.gif)
![rb_block35.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/e3fc6556-1650-01d1-e2db-0fb4fb7f01bf.gif)


### B-3． ゲームオーバー画面から再開させる(rb_block36.html）
ゲームオーバー画面から、特定のキーを押すことで、ゲームが再開するようにします。

キーが押されたかどうかは、`Input.key_down?(キーボード定数)`で調べます。

あとは、再開画面をどう設定するかは、自由です。（ここでは、残ったブロックはそのままで、ボールを初期条件に戻しています。）


```rb_block36.rb
include DX
# 初期設定用のコード (your setup code here)
Window.width   = 640
Window.height  = 480
Window.bgcolor = C_BLACK

# 壁の厚み：左、右、上；20

# ボール、バー、ブロックはItemクラスにする
class Item
  def initialize(x, y, image)
    @x = x
    @y = y
    @image  = image
    @width  = image.width
    @height = image.height
  end
  attr_accessor :x, :y, :image, :width, :height

  # 衝突判定
  def collision?(item_b)
    a_x0 = self.x
    a_x1 = self.x + self.width
    a_y0 = self.y
    a_y1 = self.y + self.height
    
    b_x0 = item_b.x
    b_x1 = item_b.x + item_b.width
    b_y0 = item_b.y
    b_y1 = item_b.y + item_b.height
    
    if a_x0 < b_x1 &&
       a_x1 > b_x0 &&
       a_y0 < b_y1 && 
       a_y1 > b_y0
      
      true
    end
  end
end


# バーの準備
img_bar = Image.load("bar.png")
bar = Item.new(250, 480 - img_bar.height, img_bar)

# ボールの準備
img_ball = Image.load("ball.png")
ball = Item.new(300, 400, img_ball)
dx =  2   # ボールのスピード（x方向）
dy = -2   # ボールのスピード（y方向）

# ブロックの準備
img_block = Image.load("block.png")

# ブロック群の初期化
blocks = []
10.times do |x|
  5.times do |y|
    blocks << Item.new(21 + (img_block.width + 2) * x, 21 + (img_block.height + 2) * y, img_block)
  end
end

# フォントの準備
font = Font.new(24)

# 1秒当たりの描画回数の設定（初期値：60）
#Window.fps = 30


# メインループ
Window.loop do
  # バーを動かす
  #bar.x += Input.x * 4       # 左右キーの場合
  bar.x = Input.mouse_x       # マウスの場合
  if bar.x < 20
    bar.x = 20
  elsif bar.x > 640 - 20 - bar.width
    bar.x = 640 - 20 - bar.width
  end


  # ボールをy方向に動かす
  ball.y += dy

  # バーとの衝突判定
  if ball.collision?(bar)
    if ball.y + ball.height  <=  480 - bar.height + dy.abs
      ball.y -= dy
      dy = -dy
    end
  end

  # ブロックとの衝突判定（y方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.y -= dy
      dy = -dy
      true
    end
  end

  # 壁に当たったら、跳ね返る(y方向)
  if ball.y < 20
    ball.y -= dy
    dy = -dy
  end


  # ボールをx方向に動かす
  ball.x += dx

  # ブロックとの衝突判定（x方向）
  blocks.delete_if do |block|
    if ball.collision?(block)
      ball.x -= dx
      dx = -dx
      true
    end
  end
  
  # 壁に当たったら、跳ね返る（x方向）
  if ball.x < 20 || (ball.x + ball.width) > 620
    ball.x -= dx
    dx = -dx
  end


  # 画面描画
  Window.draw_box_fill(  0,   0,  20, 480, C_WHITE)
  Window.draw_box_fill(620,   0, 640, 480, C_WHITE)
  Window.draw_box_fill(  0,   0, 640,  20, C_WHITE)

  Window.draw(bar.x, bar.y, bar.image)
  Window.draw(ball.x, ball.y, ball.image)

  blocks.each do |block|
    Window.draw(block.x, block.y, block.image)
  end

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

  # ゲームオーバー画面
  if ball.y >= 480
    Window.draw_box_fill(0, 0, 640, 480, C_WHITE)
    Window.draw_font(200, 200, "ゲームオーバー", font, {:color => C_BLACK})
    Window.draw_font(200, 230, "スペースキーで続行", font, {:color => C_BLACK})  # ◆追加
    if Input.key_down?(K_SPACE)                                               # ◆追加
      ball.x = 300                                                            # ◆追加
      ball.y = 400                                                            # ◆追加
      dx =  2                                                                 # ◆追加
      dy = -2                                                                 # ◆追加
    end                                                                       # ◆追加
  end

end
```

![rb_block36_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26536/82cd6ebd-5eec-30fc-ddca-56de9c2d0f20.gif)

以上で、テキストは終わりです。

あとは皆さんでいろいろと発展させてみてください！