とりあえずアップしとくサンプル
ゲームオーバー判定が無いが。
# DXRuby0.0.5 サンプル ブロック落とし require 'dxruby' Window.caption = "ブロック落としモドキ" # ブロックデータ blank = [0, 0, 0, 0] $block = [[blank, [0, 1, 1, 0], [0, 1, 1, 0], blank], [blank, [1, 1, 1, 1], [0, 0, 0, 0], blank], [blank, [0, 0, 1, 1], [0, 1, 1, 0], blank], [blank, [0, 1, 1, 0], [0, 0, 1, 1], blank], [blank, [0, 1, 1, 1], [0, 1, 0, 0], blank], [blank, [0, 1, 1, 1], [0, 0, 0, 1], blank], [blank, [0, 1, 1, 1], [0, 0, 1, 0], blank]] blockimage = [] # 画像データの作成 (1..7). each do |i| data = Image.new(16, 16) # ブロックの種類が多いので計算で色を作ってみた # こんなことするより画像ファイルから読むほうをオススメします data.box(0, 0, 15, 15, [255, (i / 4)*220, ((i % 4) / 2)*220, (i % 2)*220]) data.line(0, 0, 14, 0, [255, (i / 4)*128+127, ((i % 4) / 2)*128+127, (i % 2)*128+127]) data.line(0, 0, 0, 14, [255, (i / 4)*128+127, ((i % 4) / 2)*128+127, (i % 2)*128+127]) data.line(15, 1, 15, 15, [255, (i / 4)*128, ((i % 4) / 2)*128, (i % 2)*128]) data.line(1, 15, 15, 15, [255, (i / 4)*128, ((i % 4) / 2)*128, (i % 2)*128]) blockimage.push(data) end stageimage = Image.new(192, 336).box(0, 0, 191, 335, [255, 255, 255, 255]). box(16, 0, 175, 319, [255,0,0,0]) $field = Array.new(20){[1] + [nil]*10 + [1]}.push([1]*12) # 指定回数右回転 def rotation(num, angle) b = $block[num] angle.times do a = [[], [], [], []] for y in 0..3 do for x in 0..3 do a[x].push(b[3 - y][x]) end end b = a end return b end # 当たり判定 def check(b, x, y) for i in 0..3 do for j in 0..3 do if b[i][j] == 1 and $field[(y+15) / 16 + i][x / 16 + j] != nil then return true end end end return false end x = 64 # 横 y = 0 # 縦 kind = rand(7) # ブロックの種類 angle = 0 # 角度 # メインループ Window.loop do Window.draw(0, 0, stageimage) # 枠描画 # 回転操作 if Input.padPush?(P_BUTTON0) and check(rotation(kind, angle-1), x, y) == false then angle = angle == 0 ? 3 : angle - 1 end if Input.padPush?(P_BUTTON1) and check(rotation(kind, angle+1), x, y) == false then angle = angle == 3 ? 0 : angle + 1 end b = rotation(kind, angle) # 回転したデータを作成 x = x - 16 if Input.padPush?(P_LEFT) and check(b, x-16, y) == false x = x + 16 if Input.padPush?(P_RIGHT) and check(b, x+16, y) == false y = y + 1 y = y + 3 if Input.padDown?(P_DOWN) # 当たり判定 if check(b, x, y) == true then # 当たっていたら for i in 0..3 do for j in 0..3 do # フィールド配列に設定 $field[(y+15) / 16 + i - 1][x / 16 + j] = kind if b[i][j] == 1 end end x = 64 y = 0 kind = rand(7) angle = 0 for i in 0..19 do # 揃った行を削除&上に空行追加 if $field[i].index(nil) == nil then $field.delete_at(i) $field.unshift([1] + [nil]*10 + [1]) end end else # 画像描画 for i in 0..3 do for j in 0..3 do Window.draw(j * 16 + x, i * 16 + y, blockimage[kind]) if b[i][j] == 1 end end end # フィールド描画 for i in 0..19 do for j in 1..10 do Window.draw(j * 16, i * 16, blockimage[$field[i][j]]) if $field[i][j] end end break if Input.keyDown?(K_ESCAPE) end
テトリスもどきは検索するとソースがいっぱい出てくるが、作る人によってほんとにマチマチなのは、おそらくデータ構造によってプログラムが大きく変わるからだ。
つまり、初めの設計が全てである。
この点に置いて、初心者がテトリスは簡単そうだから練習に作ろう、というのはなかなか難しいのではないかと思うわけだ。
テキトーな構造で作りはじめるととんでもなく苦労することになる。
ややこしいことは避けようと思ったのだが、短くするためにアノ手コノ手になってしまった。
根本的に、データ構造の制限によりあまり短くはならない。
もっとわかりにくい構造にすれば、まだまだ行けるのだろう。
まあ、短さとわかりにくさなら7行テトリスがあることだし、競ってもしょうがなくて、ここではブログにソースを載せる限界を100行前後と勝手に定めて、そのあたりに納めるように努力してみた。