37
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2020-05-31

(2022.6.17追記:アップグレードされた「rbCanvas」が発表されました。
 → インストール不要!ブラウザだけではじめるRubyゲームプログラミング環境「rbCanvas」の紹介(DXRubyスタイル) - Qiita

概要

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

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

blocks_anime.gif

技術解説

使用ライブラリ

  • Nyle-canvas(DXRubyスタイル)

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

Nyle-canvas_editor.png

Nyle-canvas(DXRubyスタイル)

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

Nyle-canvasの使い方

下記の投稿を見てください。

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

Nyle-canvasに必要な動作環境

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

Nyle-canvasのホームページ

  • Nyle-canvasホームページ

https://spoolkitamura.github.io/nyle-canvas/
Nyle-canvas_HP.png

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

Nyle-canvasホームページ」から、「DXRubyスタイル」のリンクをクリック。
Nyle-canvas_editor.png

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

参考サイト

「DXRubyスタイル」のオリジナルであるDXRubyのページ;

 
DXRubyの使い方を解説した記事;

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

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

本テキストの実行環境

  • ブラウザ;
    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の日記」より改変

本テキストのソースコード

本テキストのライセンス

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

(Nyle-canvasのソースコードは MITライセンス)

プログラム解説

1. Nyle-canvasの使い方(概略)

Nyle-canvasの使い方については、下記の投稿を見てください。

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

1-1. Nyle-canvasエディターを開く

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

Nyle-canvas_DXRuby.png
「Nyle-canvasホームページ」
https://spoolkitamura.github.io/nyle-canvas/
から、
「DXRubyスタイル」のリンクをクリック。

Nyle-canvas_editor.png
これが、Nyle-canvasエディタ画面になります。

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

エディタ画面にはあらかじめ基本のプログラムが表示されています。
また、画面左上には各種ボタンが並んでいます。
右から、

  • ▶︎ ボタン;プログラム実行
  • ↓ ボタン;プログラム保存(ダウンロード)
  • Tボタン;フォント(文字サイズ)設定
  • ?ボタン;ヘルプ(リファレンス)画面へ

・プログラムの新規作成

ブラウザのNyle-canvas エディタ画面で 「再読み込み」をすると、最初の状態に戻ります。

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

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

1-2. プログラムの実行・再実行

プログラムは保存操作なしで、▶︎ボタンを押すだけで即実行されます。

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

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

座標は、左上が原点(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

1-5. 画像ファイルの読み込み

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

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

image_drop_anime.gif

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

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

1-6. コンソールの開き方

実行時のエラーメッセージputsなどの結果は、ブラウザのコンソールに出力されます。

error_console.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

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

2-2. 壁を出す(右側も)(rb_block02.html)

次に、右側の縦の壁を作ります。

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

右下隅はウィンドウの右下隅と同じ(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

2-3. 壁を出す(上側も)(rb_block03.html)

上側の横の壁を作ります(厚み20)。

左上隅は(0, 0)、右下隅のxはウィンドウ幅と同じ640yは壁の厚みと同じ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

2-4. バーを出す(rb_block04.html)

ボールを打ち返すバーとして、横100、縦20の水色の長方形の画像イメージ(src/image/bar.png)を用意します。

bar.png

まず、bar.pngファイルをエディタ画面に直接ドラッグ&ドロップします。これにより、Nyle-canvas内にコピーされ、エディタ画面下側の画像ファイル一覧に表示されるようになります。
rb_block04_editor.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

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

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

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

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

2-10. ボールを出す(rb_block10.html)

ボールとして、横20、縦20の赤色の円の画像イメージ(src/image/ball.png)を用意します。

ball.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

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

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

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

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
右側は壁の中まで入ってしまいました。
rb_block14.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
これで良さそうですが、よ〜く見ると一瞬、壁にボールがめり込んでいます(左右の壁とも)。
rb_block15.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
こんどこそ良さそうです。
rb_block16.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
まだ、バーでは跳ね返りません。

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

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
これで良さそうですが、バーを動かしながら横から当たった時の跳ね返りが変です。
rb_block19_a_anime.gif
rb_block19_a.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
今度は、いいようです。
rb_block20.gif

2-21. ブロックを出す(1個)(rb_block21.html)

ここからは、ブロックを作っていきます。まずは1個。

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

block.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 = 21block00_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

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

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

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

2-25. ブロックをまとめて作る(Itemクラス)(rb_block25.html)

ブロックを作る/描画するプログラムが10回も繰り返したので、まとめて作ることします。

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

1) Itemクラスというクラスを作る

ブロックを扱うのに、以下のような属性をまとめて扱えると便利です。

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

それを踏まえて、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       

これで、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 と変わっていく)

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

6) ブロック群の描画もまとめる

ブロック群blocksは配列なので、繰り返し操作する 配列.each do |配列要素| 〜 end が使えます。

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

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

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

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_aitem_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_aitem_bは、Itemクラスとする)

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

2-31. collision?Itemクラスのメソッドにする(rb_block31.html)

Rubyでは、collision?(item_a, item_b)という書き方より、item_a.collision?(item_b)という書き方が多く使われます(オブジェクト指向)。

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

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

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

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

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になったブロックを削除することができます。

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

2-33. ブロックに当たったら跳ね返る;一応完成(rb_block33.html)

ブロック当たったら跳ね返るようにします。

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

# ブロックとの衝突判定(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

応用問題

「ブロック崩し」を改良・発展させてみよう

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

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

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

B-2. ゲームオーバー画面を追加する(rb_block35.html)

ゲームオーバー画面を追加してみます。

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

ゲームオーバー画面は以下のようにして作っています。

  1. ウィンドウサイズ(640, 480)と同じ大きさの白色の四角形を描く(Window.draw_box_fill(0, 0, 640, 480, C_WHITE)

  2. 「ゲームオーバー」という文字を表示させる(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
rb_block35.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

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

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

37
55
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?