Last active
June 21, 2023 10:29
-
-
Save icculus/a5dd97bb6862e62943e7fa9266481850 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$gtk.reset | |
class TetrisGame | |
# This is just to get GTK to not complain in the console for now. | |
def serialize ; { args: '' } ; end | |
def inspect ; serialize.to_s ; end | |
def to_s ; serialize.to_s ; end | |
def render_cube_pixelpos x, y, r, g, b, a=255 | |
@args.outputs.solids << [ x, y, @boxsize, @boxsize, r, g, b, a ] | |
@args.outputs.borders << [ x, y, @boxsize, @boxsize, 255, 255, 255, a ] | |
end | |
def render_cube x, y, color | |
return if color == 0 | |
render_cube_pixelpos @grid_x + (x * @boxsize), (720 - @grid_y) - (y * @boxsize), *@color_index[color] | |
end | |
def render_cube_framing x, y, w, h | |
for i in x..(x+w)-1 do | |
render_cube i, y, 7 | |
render_cube i, (y+h)-1, 7 | |
end | |
for i in y..(y+h)-1 do | |
render_cube x, i, 7 | |
render_cube (x+w)-1, i, 7 | |
end | |
end | |
def render_grid_border | |
render_cube_framing -1, -1, @grid_w + 2, @grid_h + 2 | |
end | |
def render_piece piece, x, y | |
xpos = x | |
for xi in piece do | |
ypos = y | |
for yi in xi do | |
render_cube xpos, ypos, yi | |
ypos += 1 | |
end | |
xpos += 1 | |
end | |
end | |
def render_current_piece | |
render_piece @current_piece, @current_piece_x, @current_piece_y | |
end | |
def render_next_piece | |
@args.outputs.labels << [935, 610, "Next piece", 10, 255, 255, 255, 255 ] | |
render_cube_framing @grid_w + 4, 3, 8, 8 | |
centerx = ((6 - @next_piece.length) / 2) | |
centery = ((6 - @next_piece[0].length) / 2) | |
render_piece @next_piece, @grid_w + 5 + centerx, 4 + centery | |
end | |
def render_game_grid | |
for y in 0..@grid_h-1 do | |
for x in 0..@grid_w-1 do | |
color = @grid[x][y] | |
render_cube x, y, color | |
end | |
end | |
end | |
def render | |
@args.outputs.solids << [ 0, 0, 1280, 720, 0, 0, 0, 255 ] | |
@args.outputs.labels << [550, 726, "Dragontris", 10, 255, 255, 255, 255 ] | |
@args.outputs.labels << [75, 70, "Score: #{@score}", 10, 255, 255, 255, 255 ] | |
@args.outputs.sprites << [75, 300, 300, 300, 'console-logo.png'] | |
render_grid_border | |
render_game_grid | |
render_current_piece | |
render_next_piece | |
end | |
def select_next_piece | |
@current_piece = @next_piece | |
X = rand(6) + 1 | |
@next_piece = case X | |
when 1 then [ [ 0, X ], [ 0, X ], [ X, X ] ] # L shape | |
when 2 then [ [ X, X ], [ 0, X ], [ 0, X ] ] # other L shape | |
when 3 then [ [ X, X, X, X ] ] # straight line | |
when 4 then [ [ X, X ], [ X, X ] ] # box shape | |
when 5 then [ [ 0, X ], [ X, X ], [ X, 0 ] ] # zigzag shape | |
when 6 then [ [ X, 0 ], [ X, X ], [ X, 0 ] ] # T shape | |
end | |
@current_piece_x = 5 | |
@current_piece_y = 0 | |
end | |
def current_piece_colliding | |
xpos = @current_piece_x | |
for x in @current_piece do | |
ypos = @current_piece_y | |
for y in x do | |
if (y != 0) && ((ypos >= @grid_h) || (@grid[xpos][ypos+1] != 0)) | |
return true | |
end | |
ypos += 1 | |
end | |
xpos += 1 | |
end | |
return false | |
end | |
def rotate_piece_left | |
@current_piece = @current_piece.transpose.map(&:reverse) | |
if (@current_piece_x + @current_piece.length) >= @grid_w | |
@current_piece_x = @grid_w - @current_piece.length | |
end | |
end | |
def rotate_piece_right | |
# !!! FIXME: is there a way to transpose once to accomplish this? | |
@current_piece = @current_piece.transpose.map(&:reverse) | |
@current_piece = @current_piece.transpose.map(&:reverse) | |
@current_piece = @current_piece.transpose.map(&:reverse) | |
if (@current_piece_x + @current_piece.length) >= @grid_w | |
@current_piece_x = @grid_w - @current_piece.length | |
end | |
end | |
def plant_current_piece | |
# make this piece part of the landscape | |
xpos = @current_piece_x | |
for x in @current_piece do | |
ypos = @current_piece_y | |
for y in x do | |
@grid[xpos][ypos] = y if y != 0 | |
ypos += 1 | |
end | |
xpos += 1 | |
end | |
# Check the grid for full lines to remove. | |
for y in 0..@grid_h-1 | |
full = true | |
for x in 0..@grid_w-1 | |
if @grid[x][y] == 0 | |
full = false | |
break | |
end | |
end | |
if full # nuke this line! | |
@score += 1 | |
for i in y.downto(1) do | |
for j in 0..@grid_w-1 | |
@grid[j][i] = @grid[j][i-1] | |
end | |
end | |
for i in 0..@grid_w-1 | |
@grid[i][0] = 0 | |
end | |
end | |
end | |
select_next_piece | |
@current_piece_x = 5 | |
@current_piece_y = 0 | |
if current_piece_colliding # Collision at start? Game over. | |
@gameover = true | |
end | |
end | |
def iterate | |
c = @args.inputs.controller_one | |
k = @args.inputs.keyboard | |
if @gameover | |
@args.outputs.labels << [200, 450, "GAME OVER", 100, 255, 255, 255, 255 ] | |
if k.key_down.space || c.key_down.start | |
$gtk.reset | |
end | |
return | |
end | |
if c.key_down.left || k.key_down.left | |
@current_piece_x -= 1 if @current_piece_x > 0 | |
end | |
if c.key_down.right || k.key_down.right | |
@current_piece_x += 1 if (@current_piece_x + @current_piece.length) < @grid_w | |
end | |
if c.key_down.down || c.key_held.down || | |
k.key_down.down || k.key_held.down || | |
k.key_down.space || k.key_held.space | |
@next_move -= 10 # drop faster | |
end | |
if c.key_down.a || k.key_down.a | |
rotate_piece_left | |
end | |
if c.key_down.b || k.key_down.s | |
rotate_piece_right | |
end | |
@next_move -= 1 | |
if @next_move <= 0 # drop the piece! | |
# decide if any piece of this is touching the ground... | |
if current_piece_colliding | |
plant_current_piece | |
else | |
@current_piece_y += 1 # let it click down one space. | |
end | |
@next_move = @move_ticks # reset the move timer | |
end | |
end | |
def initialize args | |
@args = args | |
@score = 0 | |
@gameover = false | |
@move_ticks ||= 30 | |
@next_move ||= @move_ticks | |
@boxsize ||= 30 | |
@grid_w ||= 10 | |
@grid_h ||= 20 | |
@grid_x ||= (1280 - (@grid_w * @boxsize)) / 2 | |
@grid_y ||= (720 - ((@grid_h-2) * @boxsize)) / 2 | |
@grid = [] | |
@color_index = [ | |
[ 0, 0, 0 ], | |
[ 255, 0, 0 ], | |
[ 0, 255, 0 ], | |
[ 0, 0, 255 ], | |
[ 255, 255, 0 ], | |
[ 255, 0, 255 ], | |
[ 0, 255, 255 ], | |
[ 127, 127, 127 ] | |
] | |
for x in 0..@grid_w-1 do | |
@grid[x] = [] | |
for y in 0..@grid_h-1 do | |
@grid[x][y] = 0 | |
end | |
end | |
select_next_piece # queues up an initial piece. | |
select_next_piece # puts one in play | |
end | |
def tick | |
iterate | |
render | |
end | |
end | |
# This is what DragonRuby calls 60 times a second. | |
def tick args | |
args.state.game ||= TetrisGame.new args | |
args.state.game.tick | |
end | |
# end of main.rb ... | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment