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



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

def initialize
  @inside_state = nil
  @game_states = []
  @transitional_game_state = nil
  @transitional_game_state_options = {}
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.



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

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.



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

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”



199
200
201
202
# File 'lib/chingu/game_state_manager.rb', line 199

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)



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

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.



259
260
261
262
263
264
# File 'lib/chingu/game_state_manager.rb', line 259

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.



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

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.



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
184
185
# File 'lib/chingu/game_state_manager.rb', line 156

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.
  #
  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.push_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, options = {}) ⇒ Object

Pops through all game states until matching a given game state (takes either a class or instance to match).



208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/chingu/game_state_manager.rb', line 208

def pop_until_game_state(new_state, options = {})
  if new_state.is_a? Class
    raise ArgumentError, "No state of given class is on the stack" unless @game_states.any? {|s| s.is_a? new_state }

    pop_game_state(options) until current_game_state.is_a? new_state

  else
    raise ArgumentError, "State is not on the stack" unless @game_states.include? new_state

    pop_game_state(options) until current_game_state == new_state
  end
end

#previous_game_stateObject Also known as: previous

Returns the previous game state. Shortcut: “previous”



191
192
193
# File 'lib/chingu/game_state_manager.rb', line 191

def previous_game_state
  current_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.



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
141
142
143
144
145
146
147
148
# File 'lib/chingu/game_state_manager.rb', line 115

def push_game_state(state, options = {})
  options = {:setup => true, :finalize => true, :transitional => true}.merge(options)
  
  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.



101
102
103
104
105
106
107
# File 'lib/chingu/game_state_manager.rb', line 101

def switch_game_state(state, options = {})
  options = {:setup => true, :finalize => true, :transitional => true}.merge!(options)
  
  # Don't setup or finalize the underlying state, since it never becomes active.
  pop_game_state(options.merge(:setup => false))
  push_game_state(state, options.merge(:finalize => false))
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.



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

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.



247
248
249
250
251
# File 'lib/chingu/game_state_manager.rb', line 247

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