Help us understand the problem. What is going on with this article?

プログラミングの基礎力をつける:なるべく基本命令だけで作る「ブロック崩し」 on DXRuby

概要

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

以前、
DXRubyで 1ステップずつ作っていく「ブロック崩し」 - Qiita
という投稿をしました。

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

しかし、プログラミングの学習としては、便利機能に頼りすぎるのもどうなんだろうか?と思っていたところ、『プログラムはこうして作られる』という本と、その著者の平山尚さんの言葉を見つけてドキッとしました。

「なんか動くもん作れていい気になってんだろうが、ライブラリを剥ぎ取ったおまえ自身の力はその程度だ。よく鏡を見ておけ」平山 尚 @hirasho

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

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

そこで、今回はRubyとそのゲームライブラリDXRubyを使いますが、以下のような基本機能・命令だけを使うことにします。

  • Rubyは、プログラミング言語として最低限の機能

  • DXRubyは、ウィンドウの生成、座標(x,y)に点を描く、座標(x,y)の色を取得する、文字の表示、マウス/キー/カーソルキーの状態の取得のみ

今回はこの課題に挑戦してみます。

『プログラムはこうして作られる プログラマの頭の中をのぞいてみよう』(平山尚 著)

pri16.png

前の記事
DXRuby:「当たり判定」を自分で作ってみよう C. 色で判定する - Qiita

関連記事
Ruby用2Dゲームライブラリ DXRuby:使い方の初歩 - Qiita
プログラミング初心者向け:DXRubyで 1ステップずつ作っていく「ブロック崩し」 - Qiita
DXRuby:「当たり判定」を自分で作ってみよう - Qiita

技術解説

使用する基本機能・命令

前述の著書で使われた「プログラミング言語 Sunaba」を参考にして以下の通りとしました。

→ プログラミング言語Sunaba
https://hirasho.github.io/Sunaba/


● Ruby

  • 定数 変数 true false nil

  • 数値 文字 文字列 ' ''

  • 演算子/式

 =(代入)
 + - * / % < > <= => == != ( )
 && ||

  • 制御構造

 while~end

 if~(else)~end

 return

 break

  • 関数

 def~end

  • その他

 require puts p #(コメント)

※クラス、配列、ハッシュ、do~end、each などは使わない


● DXRuby

○ Image(Imageクラスはスクリーン以外は使わない)

  • $screen = Image.new(640, 480) (ウィンドサイズのスクリーンの設定)
  • $screen[x, y]    (色の取得)
  • $screen[x, y] = 色  (色の設定;これでドット(点)を描く)
  • 色定数

○ Window

  • Window.loop do~end    (ウィンドウの生成、更新)
  • Window.draw(x, y, $screen) (これでドット(点)を描く)
  • Window.draw_font()     (文字の表示)

○ Input

  • Input.x        (カーソルキー←→の押下の取得)
  • Input.y        (カーソルキー↑↓の押下の取得)
  • Input.mouse_pos_x  (マウス位置xの取得)
  • Input.mouse_pos_y  (マウス位置yの取得)
  • Input.key_down?   (キーボードの押下の取得)

○ Font

 Font.new()   (文字フォントの設定)

※Spriteクラス、衝突判定などは使わない


ソースコード

https://github.com/noanoa07/dxruby_blocks

使用ライブラリ

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

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

  • Window.loopが複数置ける

  • マウス位置を取得するInput.mouse_pos_xInput.mouse_pos_yの新しい書き方として、Input.mouse_xInput.mouse_yが追加

→ DXRuby 1.4.6:更新履歴

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

DXRubyインストールの注意点

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

参考サイト

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

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

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

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

→ プログラミング言語 Sunaba で「ブロック崩し」を作ってみた - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/1979433.html

このテキスト関連のブログ記事です。

ライセンス

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

プログラム解説

0. 練習:ウィンドウを表示

ウィンドウを表示するために、ウィンドウサイズ 640×480(色は透明)の$screenイメージを作成し、Window.drawで描画します。($でグローバル変数にしています。)

→ DXRuby 1.4.1 リファレンス:Imageクラス Image.new
http://dxruby.osdn.jp/DXRubyReference/200953184038328.htm

→ DXRubyリファレンス:チュートリアル 2. 画像の読み込みと描画
http://mirichi.github.io/dxruby-doc/tutorial/basic.html

pri_00.rb
require 'dxruby'

$screen = Image.new(640, 480)

Window.loop do
  Window.draw(0, 0, $screen)
end

pri00.png

1. 練習:点(ドット)を表示する

座標(300, 200)に白色の点(ドット)を表示させてみます。

$screen上の座標(x,y)に色を指定することで、点(ドット)を表示させられます。
これには、イメージ[x, y] = 色を使います。

色の指定は、「DXRubyリファレンス:色配列と色定数について」
http://mirichi.github.io/dxruby-doc/api/constant_color.html

を見てください。

→ DXRuby 1.4.1 リファレンス:Imageクラス Image#[x, y]=color
http://dxruby.osdn.jp/DXRubyReference/200953184038328.htm

pri_01.rb
require 'dxruby'

$screen = Image.new(640, 480)

Window.loop do
  $screen[300, 200] = C_WHITE

  Window.draw(0, 0, $screen)
end

pri01.png
(よく見ると、画面中央やや上に白色の点が描かれています。)

2. 練習:点で線を描く

次は、長さ100の線を描いてみます。

線は点(ドット)の集まりとして描画します。

今回、繰り返しはwhile~endのみを使います。

pri_02.rb
require 'dxruby'

$screen = Image.new(640, 480)

Window.loop do
  width = 0
  while width < 100
    $screen[300 + width, 200] = C_WHITE
    width = width + 1
  end

  Window.draw(0, 0, $screen)
end

pri02.png

3. 練習:点で四角(トウフ)を描く

線が描けたので、四角(トウフ)を描きます。
二重ループを使います。

  • pri_03.rb(失敗!四角にならない)
pri_03.rb
require 'dxruby'

$screen = Image.new(640, 480)

Window.loop do
  width  = 0
  height = 0
  while width < 100
    while height < 80
      $screen[300 + width, 200 + height] = C_WHITE
      height = height + 1
    end
    width = width + 1
  end

  Window.draw(0, 0, $screen)
end

pri03.png

二重ループの初期値の設定の間違いです。(ありがち?)

書き直します。

pri_04.rb
require 'dxruby'

$screen = Image.new(640, 480)

Window.loop do
  width = 0
  while width < 100
    height = 0
    while height < 80
      $screen[300 + width, 200 + height] = C_WHITE
      height = height + 1
    end
    width = width + 1
  end

  Window.draw(0, 0, $screen)
end

pri04.png

4. ブロック崩し:壁を描く

それでは、ブロック崩しの壁を描いていきます。

まず、左壁(位置(0, 0)、大きさ(横 20、縦 480) 、白色)
を作ります。

pri_05.rb
require 'dxruby'

$screen = Image.new(640, 480)

Window.loop do
  x0 = 0
  y0 = 0
  width = 0
  while width < 20
    height = 0
    while height < 480
      $screen[x0 + width, y0 + height] = C_WHITE
      height = height + 1
    end
    width = width + 1
  end

  Window.draw(0, 0, $screen)
end

pri05.png

5. ブロック崩し:壁を複数描く

もう一つ、上壁(位置(0, 0)、大きさ(横 640、縦 20)、白色)を追加します。

pri_06.rb
require 'dxruby'

$screen = Image.new(640, 480)

Window.loop do
  x0 = 0
  y0 = 0
  width0 = 0
  while width0 < 20
    height0 = 0
    while height0 < 480
      $screen[x0 + width0, y0 + height0] = C_WHITE
      height0 = height0 + 1
    end
    width0 = width0 + 1
  end

  x1 = 0
  y1 = 0
  width1 = 0
  while width1 < 640
    height1 = 0
    while height1 < 20
      $screen[x1 + width1, y1 + height1] = C_WHITE
      height1 = height1 + 1
    end
    width1 = width1 + 1
  end

  Window.draw(0, 0, $screen)
end

pri06.png

6. ブロック崩し:「四角を描く」をまとめる(関数化)

続いて、左壁(位置(620, 0)、大きさ(横 20、縦 480) 、白色)
を作ります。

コードが複雑になってきたので、「四角を描く」という処理をrectという名前にまとめます(関数化)。

def rect(引数)
  処理内容 
end

このrectを使ってコードを書いてみます。

pri_07.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

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

  Window.draw(0, 0, $screen)
end

pri07.png

7. 練習:トウフを動かす

トウフをカーソルキーで動かす試作をします。

→ DXRubyリファレンス:チュートリアル 5. カーソルキーの入力
http://mirichi.github.io/dxruby-doc/tutorial/basic.html

  • pri_08.rb(失敗!軌跡が残る)
pri_08.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

x = 300
y = 200

Window.loop do
  x = x + Input.x
  y = y + Input.y

  rect(x, y, 100, 80, C_WHITE)

  Window.draw(0, 0, $screen)
end

pri08.png
図形を動かすと、前回の位置の色がそのまま残ってしまいました。

動いて見えるには、Window.loopが一周する毎に前回の図形を消す処理が必要でした。
書き直します。

pri_09.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

x = 300
y = 200

Window.loop do
  rect(x, y, 100, 80, C_DEFAULT)  # 前回の位置のトウフの軌跡を消す

  x = x + Input.x
  y = y + Input.y

  rect(x, y, 100, 80, C_WHITE)

  Window.draw(0, 0, $screen)
end

pri09.png

8. ブロック崩し:壁とバーを描く(pri_10.rb)

図形の動かし方がわかったので、バーを描いて、マウスと共に動くようにします。

→ DXRubyリファレンス:チュートリアル 7. マウスの入力
http://mirichi.github.io/dxruby-doc/tutorial/basic.html

pri_10.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

# バーの初期位置
x = 300

Window.loop do
  rect(x, 460, 100, 20, C_DEFAULT)    # バーの軌跡を消す

  rect(  0,   0,  20, 480, C_WHITE)   # 左壁
  rect(  0,   0, 640,  20, C_WHITE)   # 上壁
  rect(620,   0,  20, 480, C_WHITE)   # 右壁

  x = Input.mouse_pos_x
  rect(x, 460, 100, 20, C_WHITE)      # バー

  Window.draw(0, 0, $screen)
end

pri10.png

9. ブロック崩し:ボールを描く(動かす)

ボールを描き、動かします。移動量は、x方向 4、y方向 -4 に設定しました。

pri_11.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

# バーの初期位置
x = 300

# ボールの初期値
ball_x = 300
ball_y = 400
dx =  4
dy = -4

Window.loop do
  rect(x, 460, 100, 20, C_DEFAULT)         # バーの軌跡を消す
  rect(ball_x, ball_y, 20, 20, C_DEFAULT)  # ボールの軌跡を消す

  rect(  0,   0,  20, 480, C_WHITE)   # 左壁
  rect(  0,   0, 640,  20, C_WHITE)   # 上壁
  rect(620,   0,  20, 480, C_WHITE)   # 右壁

  x = Input.mouse_pos_x
  rect(x, 460, 100, 20, C_WHITE)      # バー

  ball_x = ball_x + dx
  ball_y = ball_y + dy
  rect(ball_x, ball_y, 20, 20, C_RED) # ボール

  Window.draw(0, 0, $screen)
end

pri11.png

10. 練習:衝突判定の試作

衝突判定を作ります。判定方法は、色で判定する方法にします。
DXRuby:「当たり判定」を自分で作ってみよう C. 色で判定する - Qiita
で使った方法です。

→ 「ブロック崩し」追加課題 1c);衝突判定の自作(色) - noanoa 日々の日記
http://blog.livedoor.jp/noanoa07/archives/2052899.html

10-1. 大きさ1ドット(点)での衝突判定

衝突判定atari?(x, y)を作ります。座標(x, y) の色が透明(C_DEFAULT)以外なら衝突と判定します。

マウスの座標(x, y)と、壁との衝突/非衝突をターミナル(コマンドプロンプト)にtrue/falseで出力します。

pri_12.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

def atari?(x, y)                       # 衝突判定(1ドット)
  if $screen[x,y] == C_DEFAULT
    return false
  end
  true
end

Window.loop do
  rect(  0,   0,  20, 480, C_WHITE)   # 左壁
  rect(  0,   0, 640,  20, C_WHITE)   # 上壁
  rect(620,   0,  20, 480, C_WHITE)   # 右壁

  x = Input.mouse_pos_x
  y = Input.mouse_pos_y

  p result =  atari?(x, y)            # マウスの位置と壁の衝突判定

  Window.draw(0, 0, $screen)
end

pri12a.png

pri12b.png

10-2. 四角形での衝突判定

四角形が、壁と衝突しているかをatari_4?で判定します。

衝突/非衝突の結果をターミナル(コマンドプロンプト)にtrue/falseで出力しつつ、四角形の色も/にします。

pri_13.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

def atari?(x, y)                       # 衝突判定(1ドット)
  if $screen[x,y] == C_DEFAULT
    return false
  end
  true
end

def atari_4?(x, y, width, height)      # 衝突判定(四角)
  atari?(x, y)         || atari?(x + width, y) ||
  atari?(x, y + width) || atari?(x + width, y + width)
end

# 四角の初期値
x = 200
y = 300
width  = 40
height = 30

Window.loop do
  rect(x, y, width, height, C_DEFAULT) # 四角の軌跡を消す

  rect(  0,   0,  20, 480, C_WHITE)    # 左壁
  rect(  0,   0, 640,  20, C_WHITE)    # 上壁
  rect(620,   0,  20, 480, C_WHITE)    # 右壁

  x = Input.mouse_pos_x
  y = Input.mouse_pos_y

  p result =  atari_4?(x, y, width, height)
  if result
    rect(x, y, width, height, C_RED)
  else
    rect(x, y, width, height, C_WHITE)
  end

  Window.draw(0, 0, $screen)
end

pri13a.png

pri13b.png

11. ブロック崩し:壁とバーで跳ね返る

衝突判定を使って、ボールが壁とバーで跳ね返るようにします。

pri_14.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

def atari?(x, y)                       # 衝突判定(1ドット)
  if $screen[x,y] == C_DEFAULT
    return false
  end
  true
end

def atari_4?(x, y, width, height)      # 衝突判定(四角)
  atari?(x, y)         || atari?(x + width, y) ||
  atari?(x, y + width) || atari?(x + width, y + width)
end

# バーの初期位置
x = 300

# ボールの初期値
ball_x = 300
ball_y = 400
dx =  4
dy = -4

Window.loop do
  rect(x, 460, 100, 20, C_DEFAULT)         # バーの軌跡を消す
  rect(ball_x, ball_y, 20, 20, C_DEFAULT)  # ボールの軌跡を消す

  rect(  0,   0,  20, 480, C_WHITE)   # 左壁
  rect(  0,   0, 640,  20, C_WHITE)   # 上壁
  rect(620,   0,  20, 480, C_WHITE)   # 右壁

  x = Input.mouse_pos_x
  rect(x, 460, 100, 20, C_WHITE)      # バー

  ball_x = ball_x + dx
  if atari_4?(ball_x, ball_y, 20, 20)
    ball_x = ball_x - dx
    dx = -dx
  end

  ball_y = ball_y + dy
  if atari_4?(ball_x, ball_y, 20, 20)
    ball_y = ball_y - dy
    dy = -dy
  end

  rect(ball_x, ball_y, 20, 20, C_RED) # ボール

  Window.draw(0, 0, $screen)
end

pri14.png

12. ブロック崩し:ブロックを描く

ブロック群を描画します。

pri_15.rb
require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

def atari?(x, y)                       # 衝突判定(1ドット)
  if $screen[x,y] == C_DEFAULT
    return false
  end
  true
end

def atari_4?(x, y, width, height)      # 衝突判定(四角)
  atari?(x, y)         || atari?(x + width, y) ||
  atari?(x, y + width) || atari?(x + width, y + width)
end

def block(x, y, color)                 # ブロック1つ
  rect(x, y, 58, 18, color)
end

def blocks                             # ブロック群を描画する
  count_x = 0
  while count_x < 10
    count_y = 0
    while count_y < 5
      x = 21 + 60 * count_x
      y = 21 + 20 * count_y
      block(x, y, C_WHITE)
      count_y = count_y + 1
    end
  count_x = count_x + 1
  end
end

# バーの初期位置
x = 300

# ボールの初期値
ball_x = 300
ball_y = 400
dx =  4
dy = -4

Window.loop do
  rect(x, 460, 100, 20, C_DEFAULT)         # バーの軌跡を消す
  rect(ball_x, ball_y, 20, 20, C_DEFAULT)  # ボールの軌跡を消す

  rect(  0,   0,  20, 480, C_WHITE)   # 左壁
  rect(  0,   0, 640,  20, C_WHITE)   # 上壁
  rect(620,   0,  20, 480, C_WHITE)   # 右壁

  x = Input.mouse_pos_x
  rect(x, 460, 100, 20, C_WHITE)      # バー

  ball_x = ball_x + dx
  if atari_4?(ball_x, ball_y, 20, 20)
    ball_x = ball_x - dx
    dx = -dx
  end

  ball_y = ball_y + dy
  if atari_4?(ball_x, ball_y, 20, 20)
    ball_y = ball_y - dy
    dy = -dy
  end

  rect(ball_x, ball_y, 20, 20, C_RED) # ボール

  blocks                              # ブロック群

  Window.draw(0, 0, $screen)
end

pri15.png

13. ブロック崩し:ブロックとの衝突判定(衝突したら消す)をする(完成)

衝突したブロックの (x, y) を計算して、ブロックを消す処理を追加します。
ブロック群の初期状態(白色)を設定する処理が必要になります。

pri_16.rb
# 基本機能だけでブロック崩し:衝突ブロックを消す(完成)

require 'dxruby'

$screen = Image.new(640, 480)

def rect(x, y, width, height, color)   # 四角を描画する
  w = 0
  while w < width
    h = 0
    while h < height
      $screen[x + w, y + h] = color
      h = h + 1
    end
    w = w + 1
  end
end

def atari?(x, y)                       # 衝突判定(1ドット)
  if $screen[x,y] == C_DEFAULT
    return false
  end
  true
end

def atari_4?(x, y, width, height)      # 衝突判定(四角)
  atari?(x, y)         || atari?(x + width, y) ||
  atari?(x, y + width) || atari?(x + width, y + width)
end

def block(x, y, color)                 # ブロック1つ
  rect(x, y, 58, 18, color)
end

def blocks                             # ブロック群を描画する
  count_x = 0
  while count_x < 10
    count_y = 0
    while count_y < 5
      x = 21 + 60 * count_x
      y = 21 + 20 * count_y
      block(x, y, $screen[x, y])       # 色は前回の色と同じにする
      count_y = count_y + 1
    end
  count_x = count_x + 1
  end
end

def vanish_block(x, y)                 # ブロックを消去する
  if (20 < x && x < 600) && (20 < y && y < 120)
    rect_x = x - (x - 21) % 60         # 衝突位置から衝突ブロックの
    rect_y = y - (y - 21) % 20         # (x, y)を計算する
    block(rect_x, rect_y, C_DEFAULT)
  end
end

def initialize_blocks                  # ブロック群の初期色を白にする
  count_x = 0
  while count_x < 10
    count_y = 0
    while count_y < 5
      x = 21 + 60 * count_x
      y = 21 + 20 * count_y
      $screen[x, y] = C_WHITE
      count_y = count_y + 1
    end
  count_x = count_x + 1
  end
end

# バーの初期位置
x = 300

# ボールの初期値
ball_x = 300
ball_y = 400
dx =  4
dy = -4

# ブロック群の初期色の設定
initialize_blocks

Window.loop do
  rect(x, 460, 100, 20, C_DEFAULT)         # バーの軌跡を消す
  rect(ball_x, ball_y, 20, 20, C_DEFAULT)  # ボールの軌跡を消す

  rect(  0,   0,  20, 480, C_WHITE)   # 左壁
  rect(  0,   0, 640,  20, C_WHITE)   # 上壁
  rect(620,   0,  20, 480, C_WHITE)   # 右壁

  x = Input.mouse_pos_x
  rect(x, 460, 100, 20, C_WHITE)      # バー

  ball_x = ball_x + dx
  if atari_4?(ball_x, ball_y, 20, 20)
    vanish_block(ball_x, ball_y)      # 衝突ブロックを消す
    ball_x = ball_x - dx
    dx = -dx
  end

  ball_y = ball_y + dy
  if atari_4?(ball_x, ball_y, 20, 20)
    vanish_block(ball_x, ball_y)      # 衝突ブロックを消す
    ball_y = ball_y - dy
    dy = -dy
  end

  rect(ball_x, ball_y, 20, 20, C_RED) # ボール

  blocks                              # ブロック群

  Window.draw(0, 0, $screen)
end

pri16.png
描画処理が追いつかず、ボールの移動スピードが低下してしまいました。
改良の余地があるようです。

参考

プログラミング初心者向け:DXRubyで 1ステップずつ作っていく「ブロック崩し」 - Qiita
で作った「ブロック崩し」のプログラムです。

block28.rb
require 'dxruby'

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

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

walls = [bar, lwall, rwall, twall]

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

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

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


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

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

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

  ball.draw

  Sprite.draw(blocks)
end

block28.png

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away