Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Ruby2D を使ったテトリス
require "ruby2d"
include Ruby2D::DSL
Wait = 18
class Tetromino
def initialize
@pat = Array.new(4)
pats = [["1111"], ["11", "11"], ["011", "110"], ["110", "011"],
["100", "111"], ["001", "111"], ["010", "111"]]
@num = rand(1..pats.size)
@pat[0] = pats.map {|pt| pt.map {|st| st.chars.map(&:to_i)} }[@num - 1]
(1..3).each do |i|
@pat[i] = @pat[i - 1].reverse.transpose #右回転
end
@dir = 0
@x, @y = 3, 0
end
attr_accessor :x, :y
def rotate(n)
@dir = (@dir + n) % 4
end
def get
@pat[@dir].map {|row| row.map {|i| i * @num} }
end
def width
@pat[@dir].first.size
end
def height
@pat[@dir].size
end
end
class Field
Width, Height = 10, 20
Margin = 30
BlockMargin = 1
BlockSide = 25
S = BlockMargin * 2 + BlockSide
W = Margin * 2 + S * Width
H = Margin * 2 + S * Height
Color = ["#158FAC", "#F1F101", "#2FFF43", "#DF0F0F",
"#5858FF", "#FFB950", "#FF98F3"]
def initialize
set width: W, height: H, title: "Tetris Ruby2D"
Rectangle.new x: 0, y: 0, width: W, height: H, color: "#ABF8FC", z: 0
Rectangle.new x: Margin, y: Margin,
width: W - 2 * Margin, height: H - 2 * Margin,
color: "black", z: 0
@blocks = Height.times.map {|y|
Width.times.map {|x|
Square.new x: Margin + BlockMargin + S * x,
y: Margin + BlockMargin + S * y,
size: BlockSide, color: "red", z: 10
}
}
@field = @blocks.map {Array.new(Width, 0)}
end
def render
Height.times do |y|
Width.times do |x|
@blocks[y][x].color = Color[@field[y][x] - 1]
@field[y][x].nonzero? ? @blocks[y][x].add : @blocks[y][x].remove
end
end
end
def birth
@piece = Tetromino.new
collision? ? raise("game over") : write_to_field
end
def write_to_field
x, y = @piece.x, @piece.y
@piece.get.map.with_index {|row, dy|
row.each_index {|dx| @field[y + dy][x + dx] = row[dx] if row[dx].nonzero?}
}
end
def delete_from_field
x, y = @piece.x, @piece.y
@piece.get.map.with_index {|row, dy|
row.each_index {|dx| @field[y + dy][x + dx] = 0 if row[dx].nonzero?}
}
end
def one_down
delete_from_field
collision_flag = false
@piece.y += 1
if collision?
@piece.y -= 1
collision_flag = true
end
write_to_field
return collision_flag
end
def collision?
x, y = @piece.x, @piece.y
return true if y + @piece.height > Height || x + @piece.width > Width
@piece.get.map.with_index {|row, dy|
row.map.with_index {|a, dx| a.nonzero? && @field[y + dy][x + dx].nonzero?}.any?
}.any?
end
def delete_blocks
Height.times do |y|
if @field[y].all?(&:nonzero?)
@field.delete_at(y)
@field.unshift(Array.new(Width, 0))
return true
end
end
false
end
def move(dx)
delete_from_field
@piece.x += dx
@piece.x -= dx if @piece.x < 0 || collision?
write_to_field
end
def rotate
delete_from_field
@piece.rotate(1)
@piece.rotate(-1) if collision?
write_to_field
end
end
f = Field.new
t = 1
deleting_continues = false #ブロックを消す作業が終っていなければtrue
collision_flag = false #これ以上テトロミノが落下できなければtrue
command = nil
wait = Wait
on :key_down do |event|
command = case event.key
when "left" then "left"
when "right" then "right"
when "up" then "rotate"
when "down" then "down"
else nil
end
end
on :controller_button_down do |event|
command = case event.button
when :left then "left"
when :right then "right"
when :a then "rotate"
when :down then "down"
else nil
end
end
f.birth
f.render
update do
unless collision_flag
case command
when "left" then f.move(-1)
when "right" then f.move(1)
when "rotate" then f.rotate
when "down" then wait = 2
end
command = nil
end
collision_flag = f.one_down if (t % wait).zero? && !collision_flag #落下できるならひとつ落下
#消せる行があるか
if (deleting_continues || collision_flag) && (t % 30).zero?
deleting_continues = f.delete_blocks #消せる行があれば一行消す
#すべて消し終わったあとの処理
unless deleting_continues
wait = Wait
collision_flag = false
f.birth
end
end
t += 1
f.render
end
show
@Nakilon

This comment has been minimized.

Copy link

@Nakilon Nakilon commented May 9, 2019

temp.rb:83:in `birth': game over (RuntimeError)

nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment