Class: GameWindow

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

Overview

The Gosu::Window is always the “environment” of our game It also provides the pulse of our game

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(player_name, hostname, port = DEFAULT_PORT, profile = false) ⇒ GameWindow

Returns a new instance of GameWindow.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/game_2d/game_window.rb', line 26

def initialize(player_name, hostname, port=DEFAULT_PORT, profile=false)
  @conn_update_total = @engine_update_total = 0.0
  @conn_update_count = @engine_update_count = 0
  @profile = profile

  super(SCREEN_WIDTH, SCREEN_HEIGHT, false, 16)
  self.caption = "Ruby Gosu Game"

  @pressed_buttons = []

  @background_image = Gosu::Image.new(self, media("Space.png"), true)
  @animation = Hash.new do |h, k|
    h[k] = Gosu::Image::load_tiles(
      self, k, Entity::CELL_WIDTH_IN_PIXELS, Entity::CELL_WIDTH_IN_PIXELS, false)
  end

  @cursor_anim = @animation[media("crosshair.gif")]

  @beep = Gosu::Sample.new(self, media("Beep.wav")) # not used yet

  @font = Gosu::Font.new(self, Gosu::default_font_name, 20)

  # Local settings
  @local = {
    :create_npc => {
      :type => 'Entity::Block',
      :hp   => 5,
      :snap => false,
    },
  }
  snap_text = lambda do |item|
    @local[:create_npc][:snap] ? "Turn snap off" : "Turn snap on"
  end

  object_type_submenus = [
    ['Dirt',       'Entity::Block',    5],
    ['Brick',      'Entity::Block',    10],
    ['Cement',     'Entity::Block',    15],
    ['Steel',      'Entity::Block',    20],
    ['Unlikelium', 'Entity::Block',    25],
    ['Titanium',   'Entity::Titanium', 0]
  ].collect do |type_name, class_name, hp|
    MenuItem.new(type_name, self, @font) do |item|
      @local[:create_npc][:type] = class_name
      @local[:create_npc][:hp] = hp
    end
  end
  object_type_menu = Menu.new('Object type', self, @font,
    *object_type_submenus)

  object_creation_menu = Menu.new('Object creation', self, @font,
    MenuItem.new('Object type', self, @font) { object_type_menu },
    MenuItem.new(snap_text, self, @font) do
      @local[:create_npc][:snap] = !@local[:create_npc][:snap]
    end,
    MenuItem.new('Save!', self, @font) { @conn.send_save }
  )
  main_menu = Menu.new('Main menu', self, @font,
    MenuItem.new('Object creation', self, @font) { object_creation_menu },
    MenuItem.new('Quit!', self, @font) { shutdown }
  )
  @menu = @top_menu = MenuItem.new('Click for menu', self, @font) { main_menu }

  # Connect to server and kick off handshaking
  # We will create our player object only after we've been accepted by the server
  # and told our starting position
  @conn = ClientConnection.new(hostname, port, self, player_name)
  @engine = @conn.engine = ClientEngine.new(self)
  @run_start = Time.now.to_f
  @update_count = 0
end

Instance Attribute Details

#animationObject (readonly)

Returns the value of attribute animation.



23
24
25
# File 'lib/game_2d/game_window.rb', line 23

def animation
  @animation
end

#fontObject (readonly)

Returns the value of attribute font.



23
24
25
# File 'lib/game_2d/game_window.rb', line 23

def font
  @font
end

#player_idObject

Returns the value of attribute player_id.



24
25
26
# File 'lib/game_2d/game_window.rb', line 24

def player_id
  @player_id
end

Instance Method Details

#button_down(id) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/game_2d/game_window.rb', line 164

def button_down(id)
  case id
    when Gosu::KbP then @conn.send_ping
    when Gosu::KbEscape then @menu = @top_menu
    when Gosu::MsLeft then # left-click
      if new_menu = @menu.handle_click
        # If handle_click returned anything, the menu consumed the click
        # If it returned a menu, that's the new one we display
        @menu = (new_menu.respond_to?(:handle_click) ? new_menu : @top_menu)
      else
        send_fire
      end
    when Gosu::MsRight then # right-click
      send_create_npc
    else @pressed_buttons << id
  end
end

#drawObject



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/game_2d/game_window.rb', line 138

def draw
  @background_image.draw(0, 0, ZOrder::Background)
  return unless @player_id
  @camera_x, @camera_y = space.good_camera_position_for(player, SCREEN_WIDTH, SCREEN_HEIGHT)
  translate(-@camera_x, -@camera_y) do
    (space.players + space.npcs).each {|entity| entity.draw(self) }
  end

  space.players.sort.each_with_index do |player, num|
    @font.draw("#{player.player_name}: #{player.score}", 10, 10 * (num * 2 + 1), ZOrder::Text, 1.0, 1.0, Gosu::Color::YELLOW)
  end

  @menu.draw

  cursor_img = @cursor_anim[Gosu::milliseconds / 50 % @cursor_anim.size]
  cursor_img.draw(
    mouse_x - cursor_img.width / 2.0,
    mouse_y - cursor_img.height / 2.0,
    ZOrder::Cursor,
    1, 1, Gosu::Color::WHITE, :add)
end

#draw_box_at(x1, y1, x2, y2, c) ⇒ Object



160
161
162
# File 'lib/game_2d/game_window.rb', line 160

def draw_box_at(x1, y1, x2, y2, c)
  draw_quad(x1, y1, c, x2, y1, c, x2, y2, c, x1, y2, c, ZOrder::Highlight)
end

#handle_inputObject

Dequeue an input event



229
230
231
232
233
# File 'lib/game_2d/game_window.rb', line 229

def handle_input
  return if player.falling?
  move = move_for_keypress
  @conn.send_move move # also creates a delta in the engine
end

#media(filename) ⇒ Object



98
99
100
# File 'lib/game_2d/game_window.rb', line 98

def media(filename)
  "#{File.dirname __FILE__}/../../media/#{filename}"
end

#mouse_coordsObject

X/Y position of the mouse (center of the crosshairs), adjusted for camera



191
192
193
194
195
196
197
# File 'lib/game_2d/game_window.rb', line 191

def mouse_coords
  # For some reason, Gosu's mouse_x/mouse_y return Floats, so round it off
  [
    (mouse_x.round + @camera_x) * Entity::PIXEL_WIDTH,
    (mouse_y.round + @camera_y) * Entity::PIXEL_WIDTH
  ]
end

#move_for_keypressObject

Check keyboard, return a motion symbol or nil



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/game_2d/game_window.rb', line 238

def move_for_keypress
  # Generated once for each keypress
  until @pressed_buttons.empty?
    button = @pressed_buttons.shift
    case button
      when Gosu::KbUp, Gosu::KbW
        return (player.building?) ? :rise_up : :flip
    end
  end

  # Continuously-generated when key held down
  case
    when button_down?(Gosu::KbLeft), button_down?(Gosu::KbA)
      :slide_left
    when button_down?(Gosu::KbRight), button_down?(Gosu::KbD)
      :slide_right
    when button_down?(Gosu::KbRightControl), button_down?(Gosu::KbLeftControl)
      :brake
    when button_down?(Gosu::KbDown), button_down?(Gosu::KbS)
      :build
  end
end

#playerObject



106
107
108
# File 'lib/game_2d/game_window.rb', line 106

def player
  space[@player_id]
end

#send_create_npcObject



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/game_2d/game_window.rb', line 199

def send_create_npc
  x, y = mouse_coords

  if @local[:create_npc][:snap]
    # When snap is on, we want the upper-left corner of the cell we clicked in
    x = (x / Entity::WIDTH) * Entity::WIDTH
    y = (y / Entity::HEIGHT) * Entity::HEIGHT
  else
    # When snap is off, we want the click to be the new entity's center, not
    # its upper-left corner
    x -= Entity::WIDTH / 2
    y -= Entity::HEIGHT / 2
  end

  @conn.send_create_npc(
    :class => @local[:create_npc][:type],
    :position => [x, y],
    :velocity => [0, 0],
    :angle => 0,
    :moving => true,
    :hp => @local[:create_npc][:hp]
  )
end

#send_fireObject



182
183
184
185
186
187
188
# File 'lib/game_2d/game_window.rb', line 182

def send_fire
  return unless @player_id
  x, y = mouse_coords
  x_vel = (x - (player.x + Entity::WIDTH / 2)) / Entity::PIXEL_WIDTH
  y_vel = (y - (player.y + Entity::WIDTH / 2)) / Entity::PIXEL_WIDTH
  @conn.send_move :fire, :x_vel => x_vel, :y_vel => y_vel
end

#shutdownObject



223
224
225
226
# File 'lib/game_2d/game_window.rb', line 223

def shutdown
  @conn.disconnect
  close
end

#spaceObject



102
103
104
# File 'lib/game_2d/game_window.rb', line 102

def space
  @engine.space
end

#updateObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/game_2d/game_window.rb', line 110

def update
  @update_count += 1

  # Handle any pending ENet events
  before_t = Time.now.to_f
  @conn.update
  if @profile
    @conn_update_total += (Time.now.to_f - before_t)
    @conn_update_count += 1
    $stderr.puts "@conn.update() averages #{@conn_update_total / @conn_update_count} seconds each" if (@conn_update_count % 60) == 0
  end
  return unless @conn.online? && @engine

  before_t = Time.now.to_f
  @engine.update
  if @profile
    @engine_update_total += (Time.now.to_f - before_t)
    @engine_update_count += 1
    $stderr.puts "@engine.update() averages #{@engine_update_total / @engine_update_count} seconds" if (@engine_update_count % 60) == 0
  end

  # Player at the keyboard queues up a command
  # @pressed_buttons is emptied by handle_input
  handle_input if @player_id

  $stderr.puts "Updates per second: #{@update_count / (Time.now.to_f - @run_start)}" if @profile
end