Class: Game

Inherits:
Gosu::Window
  • Object
show all
Defined in:
lib/tetris.rb

Overview

Main class for Tetris.

Constant Summary collapse

STATE_PLAYING =
1
STATE_END =
2

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGame

Returns a new instance of Game.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/tetris.rb', line 23

def initialize
  @screen_width = 320
  @screen_height = 640

  super(@screen_width, @screen_height, false)
  @score = 0
  @blocks = []
  @game_state = STATE_END
  @game_speed = 1 # the lower, the faster

  @game_over_text = Gosu::Image.from_text(self, 'Game Over', 'Arial', 40)
  @press_space_text = Gosu::Image.from_text(self, 'Press SPACE to start a new game', 'Arial', 15)
  @music = Gosu::Song.new('../media/Tetris.ogg')

  self.caption = "Tetris! (#{@score} Points)"
  @shape = nil
  @elapsed_seconds = 0
  @last_move_y = 0
  @last_move_x = 0
end

Instance Attribute Details

#blocksObject

Returns the value of attribute blocks.



14
15
16
# File 'lib/tetris.rb', line 14

def blocks
  @blocks
end

#current_shapeObject

Returns the value of attribute current_shape.



14
15
16
# File 'lib/tetris.rb', line 14

def current_shape
  @current_shape
end

#elapsed_secondsObject

Returns the value of attribute elapsed_seconds.



15
16
17
# File 'lib/tetris.rb', line 15

def elapsed_seconds
  @elapsed_seconds
end

#fall_speedObject

Returns the value of attribute fall_speed.



14
15
16
# File 'lib/tetris.rb', line 14

def fall_speed
  @fall_speed
end

#game_speedObject

Returns the value of attribute game_speed.



15
16
17
# File 'lib/tetris.rb', line 15

def game_speed
  @game_speed
end

#game_stateObject

Returns the value of attribute game_state.



14
15
16
# File 'lib/tetris.rb', line 14

def game_state
  @game_state
end

#last_move_xObject

Returns the value of attribute last_move_x.



16
17
18
# File 'lib/tetris.rb', line 16

def last_move_x
  @last_move_x
end

#last_move_yObject

Returns the value of attribute last_move_y.



16
17
18
# File 'lib/tetris.rb', line 16

def last_move_y
  @last_move_y
end

#scoreObject

Returns the value of attribute score.



14
15
16
# File 'lib/tetris.rb', line 14

def score
  @score
end

#screen_heightObject

Returns the value of attribute screen_height.



15
16
17
# File 'lib/tetris.rb', line 15

def screen_height
  @screen_height
end

#screen_widthObject

Returns the value of attribute screen_width.



15
16
17
# File 'lib/tetris.rb', line 15

def screen_width
  @screen_width
end

#shapeObject (readonly)

Returns the value of attribute shape.



18
19
20
# File 'lib/tetris.rb', line 18

def shape
  @shape
end

Instance Method Details

#button_down(key) ⇒ Object

better responsiveness than button_up (rotates the shape immediately)



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/tetris.rb', line 60

def button_down(key)
  if @game_state == STATE_END

    # (re)start the game
    if key == Gosu::KbSpace
      @blocks = []
      @score = 0
      @shape = nil
      self.caption = "Tetris! (#{@score} Points)"
      @game_state = STATE_PLAYING
      @music.stop

      # true indicates whether it should loop
      @music.play(true)
    end
  elsif @game_state == STATE_PLAYING
    if key == Gosu::KbSpace && !@shape.nil?
      @shape.rotation += 1
      @shape.rotation -= 1 if @shape.collides?
    end
  end
end

#button_up(key) ⇒ Object

this is a callback for key up events or equivalent (there are constants for gamepad buttons and mouse clicks)



55
56
57
# File 'lib/tetris.rb', line 55

def button_up(key)
  close if key == Gosu::KbEscape
end

#delete_linesObject

deletes complete lines returns the number of deleted lines



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/tetris.rb', line 85

def delete_lines
  lines_to_delete = []

  @shape.get_blocks.each do |block|
    sum = @blocks.count { |x| x.y == block.y }
    if sum == @screen_width / Block.width
      lines_to_delete << block.y
      @blocks.delete_if { |x| x.y == block.y }
    end
  end

  update_score(lines_to_delete)
  move_blocks_down(lines_to_delete)

  lines_to_delete
end

#drawObject



44
45
46
47
48
49
50
51
# File 'lib/tetris.rb', line 44

def draw
  @blocks.each(&:draw)
  @shape.draw unless @shape.nil?
  return if @game_state != STATE_END

  @game_over_text.draw(@screen_width / 2 - 75, @screen_height / 2 - 40, 0)
  @press_space_text.draw(@screen_width / 2 - 85, @screen_height / 2, 0)
end

#move_blocks_down(lines) ⇒ Object

moves appropriate blocks down (typically after lines removal)



111
112
113
114
115
116
117
# File 'lib/tetris.rb', line 111

def move_blocks_down(lines)
  return if lines.empty?

  @blocks.each do |block|
    block.y += lines.size * Block.height if block.y < lines.min
  end
end

#spawn_shapeObject

Spawns a new shape



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/tetris.rb', line 145

def spawn_shape
  # Add the previous shape to the block list
  unless @shape.nil?
    @shape.get_blocks.each do |block|
      @blocks << block
    end

    # erase completed lines
    delete_lines
  end

  shapes = [ShapeJ.new(self), ShapeL.new(self), ShapeI.new(self), ShapeO.new(self), ShapeT.new(self), ShapeZ.new(self), ShapeS.new(self)]
  @shape = shapes.sample

  @shape.x = Block.width * 4
  @shape.get_blocks
end

#updateObject



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/tetris.rb', line 119

def update
  update_delta

  return if @game_state != STATE_PLAYING

  # do we have a falling shape?
  if !@shape.nil? && @shape.falling?
    @shape.update
  else
    spawn_shape
    @game_state = STATE_END if @shape.collides?
  end
  # with a delta we need to express the speed of our entities in
  # terms of pixels/second
end

#update_deltaObject



135
136
137
138
139
140
141
142
# File 'lib/tetris.rb', line 135

def update_delta
  # Gosu::millisecodns returns the time since the window was created
  # Divide by 1000 since we want to work in seconds
  @current_time = Gosu.milliseconds / 1000.0
  # clamping here is important to avoid strange behaviors
  @delta = [@current_time - @elapsed_seconds, 0.25].min
  @elapsed_seconds = @current_time
end

#update_score(lines) ⇒ Object

updates score



103
104
105
106
107
108
# File 'lib/tetris.rb', line 103

def update_score(lines)
  return if lines.empty?

  @score += 2**(lines.size - 1)
  self.caption = "Tetris! (#{@score} Points)"
end