Class: Chingu::GameStateManager

Inherits:
Object
  • Object
show all
Defined in:
lib/chingu/game_state_manager.rb

Overview

GameStateManger is responsible for keeping track of game states with a simple pop/push stack.

More about the concept of states in games: gamedevgeek.com/tutorials/managing-game-states-in-c/ www.gamedev.net/community/forums/topic.asp?topic_id=477320

Chingu::Window automatically creates a @game_state_manager and makes it accessible in our game loop. By default the game loop calls update, draw, button_up(id) and button_down(id) on the active state.

Chingu Examples

Enter a new game state, Level, don’t call finalize() on the game state we’re leaving.

push_game_state(Level, :finalize => false)

Return to the previous game state, don’t call setup() on it when it becomes active.

pop_game_state(:setup => false)

If you want to use Chingus GameStateManager without Chingu::Window, see example5.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGameStateManager

Returns a new instance of GameStateManager.



47
48
49
50
51
52
53
# File 'lib/chingu/game_state_manager.rb', line 47

def initialize
  @inside_state = nil
  @game_states = []
  @transitional_game_state = nil
  @transitional_game_state_options = {}
  @previous_game_state = nil
end

Instance Attribute Details

#inside_stateObject

Returns the value of attribute inside_state.



45
46
47
# File 'lib/chingu/game_state_manager.rb', line 45

def inside_state
  @inside_state
end

Instance Method Details

#button_down(id) ⇒ Object

This method should be called from button_down(id) inside your main loop. Enables the game state manager to call button_down(id) on active game state.

If you’re using Chingu::Window instead of Gosu::Window this will automaticly be called.



256
257
258
# File 'lib/chingu/game_state_manager.rb', line 256

def button_down(id)
  current_game_state.button_down(id) if current_game_state
end

#button_up(id) ⇒ Object

This method should be called from button_up(id) inside your main loop. Enables the game state manager to call button_up(id) on active game state.

If you’re using Chingu::Window instead of Gosu::Window this will automaticly be called.



266
267
268
# File 'lib/chingu/game_state_manager.rb', line 266

def button_up(id)
  current_game_state.button_up(id)  if current_game_state
end

#clear_game_statesObject Also known as: clear

Remove all game states from stack. Shortcut: “clear”



235
236
237
238
# File 'lib/chingu/game_state_manager.rb', line 235

def clear_game_states
  @game_states.clear
  self.inside_state = nil
end

#current_game_stateObject Also known as: current

Gets the currently active gamestate (top of stack)



58
59
60
# File 'lib/chingu/game_state_manager.rb', line 58

def current_game_state
  @game_states.last
end

#drawObject

This method should be called from draw() inside your main loop. Enables the game state manager to call update() on active game state.

If you’re using Chingu::Window instead of Gosu::Window this will automaticly be called.



290
291
292
293
294
295
# File 'lib/chingu/game_state_manager.rb', line 290

def draw
  if current_game_state
    current_game_state.draw_trait
    current_game_state.draw
  end
end

#game_statesObject

Returns all gamestates with currenlty active game state on top.



66
67
68
# File 'lib/chingu/game_state_manager.rb', line 66

def game_states
  @game_states.reverse
end

#pop_game_state(options = {}) ⇒ Object Also known as: pop

Pops a state off the game state-stack, activating the previous one. By default setup() is called on the game state that becomes active. .. and finalize() is called on the game state we’re leaving.



191
192
193
194
195
196
197
198
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/chingu/game_state_manager.rb', line 191

def pop_game_state(options = {})
  options = {:setup => true, :finalize => true, :transitional => true}.merge(options)
  
  #
  # Give the soon-to-be-disabled state a chance to clean up by calling finalize() on it.
  #
  @previous_game_state = current_game_state
  current_game_state.finalize    if current_game_state.respond_to?(:finalize) && options[:finalize]

  #
  # Activate the game state "bellow" current one with a simple Array.pop
  #
  @game_states.pop
  
  # So BasicGameObject#create connects object to new state in its setup()
  # Is this doubled in GameState.initialize() ?
  self.inside_state = current_game_state
  
  # Call setup on the new current state
  current_game_state.setup       if current_game_state.respond_to?(:setup) && options[:setup]
  
  if @transitional_game_state && options[:transitional]
    # If we have a transitional, push that instead, with new_state as first argument
    transitional_game_state = @transitional_game_state.new(current_game_state, @transitional_game_state_options)
    transitional_game_state.game_state_manager = self
    self.switch_game_state(transitional_game_state, :transitional => false)
  end
  
  ## MOVED: self.inside_state = current_game_state
  self.inside_state = nil   # no longer 'inside' (as in within initialize() etc) a game state
end

#pop_until_game_state(new_state) ⇒ Object

Pops through all game states until matching a given game state



244
245
246
247
248
# File 'lib/chingu/game_state_manager.rb', line 244

def pop_until_game_state(new_state)
  while (state = @game_states.pop)
    break if state == new_state
  end
end

#previous_game_stateObject Also known as: previous

Returns the previous game state. Shortcut: “previous”



227
228
229
# File 'lib/chingu/game_state_manager.rb', line 227

def previous_game_state
  @previous_game_state
end

#push_game_state(state, options = {}) ⇒ Object Also known as: push

Adds a state to the game state-stack and activates it. By default setup() is called on the new game state .. and finalize() is called on the game state we’re leaving.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/chingu/game_state_manager.rb', line 148

def push_game_state(state, options = {})
  options = {:setup => true, :finalize => true, :transitional => true}.merge(options)

  @previous_game_state = current_game_state
  
  new_state = game_state_instance(state)
        
  if new_state
    
    # So BasicGameObject#create connects object to new state in its setup()
    self.inside_state = new_state
    
    # Make sure the game state knows about the manager
    # Is this doubled in GameState.initialize() ?
    new_state.game_state_manager = self
    
    # Call setup
    new_state.setup               if new_state.respond_to?(:setup) && options[:setup]
            
    # Give the soon-to-be-disabled state a chance to clean up by calling finalize() on it.
    current_game_state.finalize   if current_game_state.respond_to?(:finalize) && options[:finalize]
    
    if @transitional_game_state && options[:transitional]
      # If we have a transitional, push that instead, with new_state as first argument
      transitional_game_state = @transitional_game_state.new(new_state, @transitional_game_state_options)
      transitional_game_state.game_state_manager = self
      self.push_game_state(transitional_game_state, :transitional => false)
    else
      # Push new state on top of stack and therefore making it active
      @game_states.push(new_state)
    end
    ## MOVED: self.inside_state = current_game_state
  end
  
  self.inside_state = nil   # no longer 'inside' (as in within initialize() etc) a game state
end

#switch_game_state(state, options = {}) ⇒ Object Also known as: switch

Switch to a given game state, replacing the current active one. By default setup() is called on the game state we’re switching to. .. and finalize() is called on the game state we’re switching from.



102
103
104
105
106
107
108
109
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
137
138
139
140
# File 'lib/chingu/game_state_manager.rb', line 102

def switch_game_state(state, options = {})
  options = {:setup => true, :finalize => true, :transitional => true}.merge(options)

  @previous_game_state = current_game_state
  
  new_state = game_state_instance(state)
  
  if new_state
    # Make sure the game state knows about the manager
    new_state.game_state_manager = self
    
    # Give the soon-to-be-disabled state a chance to clean up by calling finalize() on it.
    current_game_state.finalize   if current_game_state.respond_to?(:finalize) && options[:finalize]
    
    # So BasicGameObject#create connects object to new state in its setup()
    # Is this doubled in GameState.initialize() ?
    self.inside_state = new_state
    
    # Call setup
    new_state.setup               if new_state.respond_to?(:setup) && options[:setup]
    
    if @transitional_game_state && options[:transitional]
      # If we have a transitional, switch to that instead, with new_state as first argument
      transitional_game_state = @transitional_game_state.new(new_state, @transitional_game_state_options)
      transitional_game_state.game_state_manager = self
      self.switch_game_state(transitional_game_state, :transitional => false)
    else
      if current_game_state.nil?
        @game_states << new_state
      else
        # Replace last (active) state with new one
        @game_states[-1] = new_state
      end
    end
    ## MOVED: self.inside_state = current_game_state
  end
  
  self.inside_state = nil   # no longer 'inside' (as in within initialize() etc) a game state
end

#transitional_game_state(game_state, options = {}) ⇒ Object

Sets a game state to be called between the old and the new game state whenever a game state is switched,pushed or popped.

The transitional game state is responsible for switching to the “new game state”. It should do so with “:transitional => false” not to create an infinite loop.

The new game state is the first argument to the transitional game states initialize().

Example:

transitional_game_state(FadeIn)
push_game_state(Level2)

would in practice become:

push_game_state(FadeIn.new(Level2))

This would be the case for every game state change until the transitional game state is removed:

transitional_game_state(nil)  # or false

Very useful for fading effect between scenes.



92
93
94
95
# File 'lib/chingu/game_state_manager.rb', line 92

def transitional_game_state(game_state, options = {})
  @transitional_game_state = game_state
  @transitional_game_state_options = options
end

#update(options = {}) ⇒ Object

This method should be called from update() inside your main loop. Enables the game state manager to call update() on active game state.

If you’re using Chingu::Window instead of Gosu::Window this will automaticly be called.



276
277
278
279
280
281
282
# File 'lib/chingu/game_state_manager.rb', line 276

def update(options = {})
  puts current_game_state.to_s  if options[:debug]
  if current_game_state
    current_game_state.update_trait
    current_game_state.update
  end
end