GTK Tetris + Cairo 튜토리얼용 Glimmer DSL

113002 단어 desktopguigtkruby
Glimmer DSL for GTK ( Ruby GNOME Desktop Development GUI Library) an issue requesting a Tetris sample 에 대한 응답으로 몇 가지 릴리스가 있었습니다. 이 프로젝트에는 이제 새로운declarative support for Cairo graphicsimplementation of the Tetris game as a sample이 포함됩니다. 또한 여기에 언급된Cairo samples의 대부분Cairo Tutorial blog post by Mohit Sindhwani ("Cairo with Ruby - Samples using RCairo")도 포함되었습니다.

다음은 (기본Glimmer DSL for GTK rewriting of Mohit's tutorial 명령형 구문 대신) 훨씬 간단하고 유지 관리하기 쉬운Glimmer DSL for GTK declarative Cairo syntax을 사용하는 RCairo입니다.

GTK용 Glimmer DSL과 함께 Ruby에서 Cairo를 사용하는 튜토리얼:



CairoGTK에서 임의의 2D 기하학적 모양을 그리는 엔진입니다.

Glimmer DSL for GTK 에서 SVG 작동 방식과 유사한 방식으로 Cairo 모양을 선언적으로 그릴 수 있지만 하나의 언어를 사용합니다. Ruby, 따라서 필요할 때 손쉽게 Ruby 로직(예: if 문 또는 각 루프)을 활용할 수 있습니다. 선언적 구문은 또한 더 단순하고 중첩 속성의 순서에 의존하지 않고 더 이해하기 쉽고 유지 관리하기 쉬운 코드를 생성합니다.

아래는 Mohit Sindhwani's blog post "Cairo with Ruby - Samples using RCairo" 에서 영감을 받아 이식한 샘플로 구성된 빠른 자습서입니다.



samples/cairo/arc.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Hello, Drawing Area!'
  default_size 256, 256

  drawing_area {
    # Surface Paint
    paint 242.25, 242.25, 242.25

    # Set up the parameters
    xc = 128.0
    yc = 128.0
    radius = 100.0
    angle1 = 45.0  * (Math::PI/180.0) # angles are specified
    angle2 = 180.0  * (Math::PI/180.0) # in radians

    # The main arc
    arc(xc, yc, radius, angle1, angle2) {
      stroke 0, 0, 0
      line_width 10
    }

    # Draw helping lines

    # First, the circle at the centre
    arc(xc, yc, 10.0, 0, 2*Math::PI) {
      fill 255, 51, 51, 0.6
    }

    # Then, the lines reaching out
    path {
      arc xc, yc, radius, angle1, angle1
      line_to xc, yc
      arc xc, yc, radius, angle2, angle2
      line_to xc, yc

      stroke 255, 51, 51, 0.6
      line_width 6
    }
  }
}.show




아크 네거티브



samples/cairo/arc_negative.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Arc Negative'
  default_size 256, 256

  drawing_area {
    # Surface Paint
    paint 255, 255, 255

    # Set up the parameters
    xc = 128.0
    yc = 128.0
    radius = 100.0
    angle1 = 45.0  * (Math::PI/180.0) # angles are specified
    angle2 = 180.0  * (Math::PI/180.0) # in radians

    # The main negative arc
    arc_negative(xc, yc, radius, angle1, angle2) {
      stroke 0, 0, 0
      line_width 10
    }

    # Draw helping lines

    # First, the circle at the centre
    arc(xc, yc, 10.0, 0, 2*Math::PI) {
      fill 255, 51, 51, 0.6
    }

    # Then, the lines reaching out
    path {
      arc(xc, yc, radius, angle1, angle1)
      line_to(xc, yc)
      arc(xc, yc, radius, angle2, angle2)
      line_to(xc, yc)

      stroke 255, 51, 51, 0.6
      line_width 6
    }
  }
}.show




클립



samples/cairo/clip.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Clip'
  default_size 256, 256

  drawing_area {
    # Surface Paint
    paint 255, 255, 255

    # Designate arc as the clipping area
    arc(128.0, 128.0, 76.8, 0, 2 * Math::PI) {
      clip true
    }

    # Rectangle will get clipped by arc
    rectangle(0, 0, 256, 256) {
      fill 0, 0, 0
    }

    # Path will get clipped by arc
    path {
      move_to 0, 0
      line_to 256, 256
      move_to 256, 0
      line_to 0, 256

      stroke 0, 255, 0
      line_width 10
    }
  }
}.show




클립 이미지



samples/cairo/clip_image.rb

require 'glimmer-dsl-gtk'
require 'net/http'

image_content = Net::HTTP.get(URI('https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-gtk/master/images/breaking-blue-wave.png'))
image_file = File.join(Dir.home, 'breaking-blue-wave.png')
File.write(image_file, image_content)

include Glimmer

window {
  title 'Clip Image'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    arc(128.0, 128.0, 76.8, 0, 2 * Math::PI) {
      clip true # designate arc as the clipping area
    }

    rectangle(0, 0, 256, 256) {
      # Source image is from:
      # - https://www.publicdomainpictures.net/en/view-image.php?image=7683&picture=breaking-blue-wave
      # Converted to PNG before using it
      image = Cairo::ImageSurface.from_png(image_file)
      w = image.width
      h = image.height

      scale 256.0/w, 256.0/h, exclude: :shape # applies scale to fill source image only
      fill image, 0, 0
    }
  }
}.show




곡선



samples/cairo/curve_to.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Curve to'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    x=25.6
    y=128.0
    x1=102.4
    y1=230.4
    x2=153.6
    y2=25.6
    x3=230.4
    y3=128.0

    path {
      move_to x, y
      curve_to x1, y1, x2, y2, x3, y3

      line_width 10
      stroke 0, 0, 0
    }

    path {
      move_to x,y
      line_to x1,y1
      move_to x2,y2
      line_to x3,y3

      line_width 6
      stroke 255, 51, 51, 0.6
    }
  }
}.show




대시



samples/cairo/dashes.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Dashes'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    dashes = [ 50.0, # ink
                       10.0,  # skip
                       10.0,  # ink
                       10.0   # skip
            ]
    offset = -50.0

    path {
      move_to 128.0, 25.6
      line_to 230.4, 230.4
      rel_line_to -102.4, 0.0
      curve_to 51.2, 230.4, 51.2, 128.0, 128.0, 128.0

      line_width 10
      dash dashes, offset
      stroke 0, 0, 0
    }
  }
}.show




채우기 및 획 2



(참고: 채우기 및 스트로크 1이 없습니다. 이것은 채우기 및 스트로크 2만 언급한 Mohit's blog post 에서 채택되었습니다.)

samples/cairo/fill_and_stroke2.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Fill and Stroke 2'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    path {
      move_to 128.0, 25.6
      line_to 230.4, 230.4
      rel_line_to -102.4, 0.0
      curve_to 51.2, 230.4, 51.2, 128.0, 128.0, 128.0
      close_path

      fill 0, 0, 255
      stroke 0, 0, 0
      line_width 10
    }

    path {
      move_to 64.0, 25.6
      rel_line_to 51.2, 51.2
      rel_line_to -51.2, 51.2
      rel_line_to -51.2, -51.2
      close_path

      fill 0, 0, 255
      stroke 0, 0, 0
      line_width 10
    }
  }
}.show




채우기 스타일



samples/cairo/fill_style.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Fill Style'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    path {
      rectangle 12, 12, 232, 70
      path { # sub-path
        arc 64, 64, 40, 0, 2*Math::PI
      }
      path { # sub-path
        arc_negative 192, 64, 40, 0, -2*Math::PI
      }

      fill_rule Cairo::FILL_RULE_EVEN_ODD
      line_width 6
      fill 0, 178.5, 0
      stroke 0, 0, 0
    }

    path {
      rectangle 12, 12, 232, 70
      path { # sub-path
        arc 64, 64, 40, 0, 2*Math::PI
      }
      path { # sub-path
        arc_negative 192, 64, 40, 0, -2*Math::PI
      }

      translate 0, 128
      fill_rule Cairo::FILL_RULE_WINDING
      line_width 6
      fill 0, 0, 229.5
      stroke 0, 0, 0
    }
  }
}.show




구배



samples/cairo/gradient.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Gradient'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    # Create the Linear Pattern
    rectangle(0, 0, 256, 256) {
      pat = Cairo::LinearPattern.new(0.0, 0.0,  0.0, 256.0)
      pat.add_color_stop_rgba(1, 0, 0, 0, 1)
      pat.add_color_stop_rgba(0, 1, 1, 1, 1)

      fill pat
    }

    # Create the radial pattern
    arc(128.0, 128.0, 76.8, 0, 2 * Math::PI) {
      pat = Cairo::RadialPattern.new(115.2, 102.4, 25.6,
                                         102.4,  102.4, 128.0)
      pat.add_color_stop_rgba(0, 1, 1, 1, 1)
      pat.add_color_stop_rgba(1, 0, 0, 0, 1)

      fill pat
    }
  }
}.show




영상



samples/cairo/image.rb

require 'glimmer-dsl-gtk'
require 'net/http'

image_content = Net::HTTP.get(URI('https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-gtk/master/images/breaking-blue-wave.png'))
image_file = File.join(Dir.home, 'breaking-blue-wave.png')
File.write(image_file, image_content)

include Glimmer

window {
  title 'Image'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    image = Cairo::ImageSurface.from_png(image_file)
    w = image.width
    h = image.height

    translate 128.0, 128.0
    rotate 45*Math::PI/180
    scale 256.0/w, 256.0/h
    translate -0.5*w, -0.5*h

    paint image, 0, 0
  }
}.show




이미지 그라데이션



samples/cairo/image_gradient.rb

require 'glimmer-dsl-gtk'
require 'net/http'

image_content = Net::HTTP.get(URI('https://raw.githubusercontent.com/AndyObtiva/glimmer-dsl-gtk/master/images/breaking-blue-wave.png'))
image_file = File.join(Dir.home, 'breaking-blue-wave.png')
File.write(image_file, image_content)

include Glimmer

window {
  title 'Image Gradient'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    image = Cairo::ImageSurface.from_png(image_file)
    w = image.width
    h = image.height

    # Load the image as a surface pattern
    pattern = Cairo::SurfacePattern.new(image)
    pattern.extend = Cairo::EXTEND_REPEAT

    # Set up the scale matrix
    pattern.matrix = Cairo::Matrix.scale(w/256.0 * 5.0, h/256.0 * 5.0)

    rectangle(0, 0, 256, 256) {
      translate 128.0, 128.0
      rotate Math::PI / 4
      scale 1/Math.sqrt(2), 1/Math.sqrt(2)
      translate -128.0, -128.0

      fill pattern
    }
  }
}.show




멀티 세그먼트 캡



samples/cairo/multi_segment_caps.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Multi Segment Caps'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    path {
      move_to 50.0, 75.0
      line_to 200.0, 75.0

      move_to 50.0, 125.0
      line_to 200.0, 125.0

      move_to 50.0, 175.0
      line_to 200.0, 175.0

      line_width 30
      line_cap Cairo::LINE_CAP_ROUND
      stroke 0, 0, 0
    }
  }
}.show




둥근 직사각형



samples/cairo/rounded_rectangle.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Rounded Rectangle'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    path {
      rounded_rectangle(25.6, 25.6, 204.8, 204.8, 20)

      fill 127.5, 127.5, 255
      line_width 10.0
      stroke 127.5, 0, 0, 0.5
    }
  }
}.show




라인 캡 설정



samples/cairo/set_line_cap.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Set line cap'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    # The main code
    path {
      move_to 64.0, 50.0
      line_to 64.0, 200.0

      line_cap Cairo::LINE_CAP_BUTT #  default
      line_width 30
      stroke 0, 0, 0
    }

    path {
      move_to 128.0, 50.0
      line_to 128.0, 200.0

      line_cap Cairo::LINE_CAP_ROUND
      line_width 30
      stroke 0, 0, 0
    }

    path {
      move_to 192.0, 50.0
      line_to 192.0, 200.0

      line_cap Cairo::LINE_CAP_SQUARE
      line_width 30
      stroke 0, 0, 0
    }

    #  draw helping lines */
    path {
      move_to 64.0, 50.0
      line_to 64.0, 200.0
      move_to 128.0, 50.0
      line_to 128.0, 200.0
      move_to 192.0, 50.0
      line_to 192.0, 200.0

      line_width 2.56
      stroke 255, 51, 51
    }
  }
}.show




라인 조인 설정



samples/cairo/set_line_join.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Set line join'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    # The main code
    path {
      move_to 76.8, 84.48
      rel_line_to 51.2, -51.2
      rel_line_to 51.2, 51.2

      line_join Cairo::LINE_JOIN_MITER # default
      line_width 40.96
      stroke 0, 0, 0
    }

    path {
      move_to 76.8, 161.28
      rel_line_to 51.2, -51.2
      rel_line_to 51.2, 51.2

      line_join Cairo::LINE_JOIN_BEVEL
      line_width 40.96
      stroke 0, 0, 0
    }

    path {
      move_to 76.8, 238.08
      rel_line_to 51.2, -51.2
      rel_line_to 51.2, 51.2

      line_join Cairo::LINE_JOIN_ROUND
      line_width 40.96
      stroke 0, 0, 0
    }
  }
}.show




텍스트



samples/cairo/text.rb

require 'glimmer-dsl-gtk'

include Glimmer

window {
  title 'Text'
  default_size 256, 256

  drawing_area {
    paint 242.25, 242.25, 242.25

    font_family = OS.linux? ? 'Sans' : (OS.mac? ? 'Helvetica' : 'Arial')

    # The main code
    path {
      move_to 10.0, 135.0
      show_text 'Hello'

      font_face font_family, Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD
      font_size 90.0
      line_width 2.56
      fill 0, 0, 0
      stroke 0, 0, 0
    }

    path {
      move_to 70.0, 165.0
      text_path 'void'

      font_face font_family, Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD
      font_size 90.0
      line_width 2.56
      fill 127.5, 127.5, 255
      stroke 0, 0, 0
    }

    # draw helping lines
    path {
      arc 10.0, 135.0, 5.12, 0, 2*Math::PI
      close_path
      arc 70.0, 165.0, 5.12, 0, 2*Math::PI

      fill 255, 51, 51, 0.6
    }
  }
}.show




테트리스 스크린샷:



다음은 Tetris 으로 작성된 declarative Cairo code using Glimmer DSL for GTK 의 스크린샷입니다.



GTK 코드용 Tetris Glimmer DSL:



카이로 사용은 대부분 Glimmer-only squarepolygon 모양 구조입니다(표준RCairo에서는 사용할 수 없음).

# From: https://github.com/AndyObtiva/glimmer-dsl-gtk#tetris

require 'glimmer-dsl-gtk'

require_relative 'tetris/model/game'

class Tetris
  include Glimmer

  BLOCK_SIZE = 25
  BEVEL_CONSTANT = 20
  COLOR_GRAY = [192, 192, 192]

  def initialize
    @game = Model::Game.new
  end

  def launch
    create_gui
    register_observers
    @game.start!
    @main_window.show
  end

  def create_gui
    @main_window = window {
      title 'Glimmer Tetris'
      default_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE # + 98

      box(:vertical) {
        tetris_menu_bar

        box(:horizontal) {
          @playfield_blocks = playfield(playfield_width: @game.playfield_width, playfield_height: @game.playfield_height, block_size: BLOCK_SIZE)

          score_board
        }

      }

      on(:key_press_event) do |widget, key_event|
        case key_event.keyval
        when 65364 # down arrow
          @game.down!
        when 32 # space
          @game.down!(instant: true)
        when 65362 # up arrow
          case @game.up_arrow_action
          when :instant_down
            @game.down!(instant: true)
          when :rotate_right
            @game.rotate!(:right)
          when :rotate_left
            @game.rotate!(:left)
          end
        when 65361 # left arrow
          @game.left!
        when 65363 # right arrow
          @game.right!
        when 65506 # right shift
          @game.rotate!(:right)
        when 65505 # left shift
          @game.rotate!(:left)
        else
          # Do Nothing
        end
      end
    }
  end

  def register_observers
    observe(@game, :game_over) do |game_over|
      if game_over
        show_game_over_dialog
      else
        start_moving_tetrominos_down
      end
    end

    @game.playfield_height.times do |row|
      @game.playfield_width.times do |column|
        observe(@game.playfield[row][column], :color) do |new_color|
          color = new_color
          block = @playfield_blocks[row][column]
          block[:background_square].fill = color
          block[:top_bevel_edge].fill = [color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT]
          block[:right_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
          block[:bottom_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
          block[:left_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
          block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
          block[:drawing_area].queue_draw
          false
        end
      end
    end

    Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
      Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
        observe(@game.preview_playfield[row][column], :color) do |new_color|
          color = new_color
          block = @preview_playfield_blocks[row][column]
          block[:background_square].fill = color
          block[:top_bevel_edge].fill = [color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT]
          block[:right_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
          block[:bottom_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
          block[:left_bevel_edge].fill = [color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT]
          block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
          block[:drawing_area].queue_draw
        end
      end
    end

    observe(@game, :score) do |new_score|
      @score_label.text = new_score.to_s
    end

    observe(@game, :lines) do |new_lines|
      @lines_label.text = new_lines.to_s
    end

    observe(@game, :level) do |new_level|
      @level_label.text = new_level.to_s
    end
  end

  def tetris_menu_bar
    menu_bar {
      menu_item(label: 'Game') { |mi|
        m = menu {
          check_menu_item(label: 'Pause') {
            on(:activate) do
              @game.paused = !@game.paused?
            end
          }

          menu_item(label: 'Restart') {
            on(:activate) do
              @game.restart!
            end
          }

          separator_menu_item

          menu_item(label: 'Exit') {
            on(:activate) do
              @main_window.close
            end
          }
        }
        mi.submenu = m.gtk
      }

      menu_item(label: 'View') { |mi|
        m = menu {
          menu_item(label: 'Show High Scores') {
            on(:activate) do
              show_high_score_dialog
            end
          }

          menu_item(label: 'Clear High Scores') {
            on(:activate) do
              @game.clear_high_scores!
            end
          }
        }
        mi.submenu = m.gtk
      }

      menu_item(label: 'Options') { |mi|
        m = menu {
          rmi = radio_menu_item(nil, 'Instant Down on Up') {
            on(:activate) do
              @game.instant_down_on_up!
            end
          }

          default_rmi = radio_menu_item(rmi.group, 'Rotate Right on Up') {
            on(:activate) do
              @game.rotate_right_on_up!
            end
          }
          default_rmi.activate

          radio_menu_item(rmi.group, 'Rotate Left on Up') {
            on(:activate) do
              @game.rotate_left_on_up!
            end
          }
        }
        mi.submenu = m.gtk
      }

      menu_item(label: 'Options') { |mi|
        m = menu {
          menu_item(label: 'About') {
            on(:activate) do
              show_about_dialog
            end
          }
        }
        mi.submenu = m.gtk
      }
    }
  end

  def score_board
    box(:vertical) {
      label
      @preview_playfield_blocks = playfield(playfield_width: Model::Game::PREVIEW_PLAYFIELD_WIDTH, playfield_height: Model::Game::PREVIEW_PLAYFIELD_HEIGHT, block_size: BLOCK_SIZE)

      label
      label('Score')
      @score_label = label

      label
      label('Lines')
      @lines_label = label

      label
      label('Level')
      @level_label = label
      label
    }
  end

  def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
    blocks = []
    box(:vertical) {
      playfield_height.times.map do |row|
        blocks << []
        box(:horizontal) {
          playfield_width.times.map do |column|
            blocks.last << block(row: row, column: column, block_size: block_size)
          end
        }
      end

      extra_content&.call
    }
    blocks
  end

  def block(row: , column: , block_size: , &extra_content)
    block = {}
    bevel_pixel_size = 0.16 * block_size.to_f
    color = Model::Block::COLOR_CLEAR
    block[:drawing_area] = drawing_area {
      size_request block_size, block_size

      block[:background_square] = square(0, 0, block_size) {
        fill *color
      }

      block[:top_bevel_edge] = polygon(0, 0, block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
        fill color[0] + 4*BEVEL_CONSTANT, color[1] + 4*BEVEL_CONSTANT, color[2] + 4*BEVEL_CONSTANT
      }

      block[:right_bevel_edge] = polygon(block_size, 0, block_size - bevel_pixel_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size, block_size) {
        fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
      }

      block[:bottom_bevel_edge] = polygon(block_size, block_size, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size, block_size - bevel_pixel_size) {
        fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
      }

      block[:left_bevel_edge] = polygon(0, 0, 0, block_size, bevel_pixel_size, block_size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
        fill color[0] - BEVEL_CONSTANT, color[1] - BEVEL_CONSTANT, color[2] - BEVEL_CONSTANT
      }

      block[:border_square] = square(0, 0, block_size) {
        stroke *COLOR_GRAY
      }

      extra_content&.call
    }
    block
  end

  def start_moving_tetrominos_down
    unless @tetrominos_start_moving_down
      @tetrominos_start_moving_down = true
      GLib::Timeout.add(@game.delay*1000) do
        @game.down! if !@game.game_over? && !@game.paused?
        true
      end
    end
  end

  def show_game_over_dialog
    message_dialog(@main_window) { |md|
      title 'Game Over!'
      text "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}"

      on(:response) do
        md.destroy
      end
    }.show

    @game.restart!
    false
  end

  def show_high_score_dialog
    game_paused = !!@game.paused
    @game.paused = true

    if @game.high_scores.empty?
      high_scores_string = "No games have been scored yet."
    else
      high_scores_string = @game.high_scores.map do |high_score|
        "#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
      end.join("\n")
    end

    message_dialog(@main_window) { |md|
      title 'High Scores'
      text high_scores_string

      on(:response) do
        md.destroy
      end
    }.show

    @game.paused = game_paused
  end

  def show_about_dialog
    message_dialog(@main_window) { |md|
      title 'About'
      text "Glimmer Tetris\n\nGlimmer DSL for GTK\n\nElaborate Sample\n\nCopyright (c) 2021-2022 Andy Maleh"

      on(:response) do
        md.destroy
      end
    }.show
  end
end

Tetris.new.launch


해피Glimmering !

좋은 웹페이지 즐겨찾기