Class: Metro::Scene

Inherits:
Object
  • Object
show all
Includes:
Draws, HasAnimations, HasEvents, SceneView, Units
Defined in:
lib/metro/scene.rb

Overview

A scene is a basic unit of a game. Within a scene you define a number of methods that handle the initial setup, event configuration, logic updating, and drawing.

A fair number of private methods within Scene are prefaced with an underscore. These methods often call non-underscored methods within those methods. This allows for scene to configure or perform some functionality, while providing an interface so that every subclass does not have to constantly call ‘super`.

See Also:

Direct Known Subclasses

GameScene, MissingScene, TransitionScene

Constant Summary

Constants included from Units

Units::Bounds

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SceneView

included, #save_view, #view, #view_content, #view_name

Methods included from HasAnimations

#animate, included

Methods included from HasEvents

included

Methods included from Draws

included

Constructor Details

#initializeScene

Note:

this method should not be overriden, otherwise the actors will perish!

Setups up the Actors for the Scene based on the ModelFactories that have been defined.

See Also:



166
167
168
169
# File 'lib/metro/scene.rb', line 166

def initialize
  add_actors_to_scene
  after_initialize
end

Instance Attribute Details

#windowObject

The window is the main instance of the game. Using window can access a lot of underlying Metro::Window, a subclass of Gosu::Window, that the Scene class is obfuscating.

See Also:



187
188
189
# File 'lib/metro/scene.rb', line 187

def window
  @window
end

Class Method Details

.after(ticks, &block) ⇒ Object

Allow the definition of a updater that will be executed when the scene starts.

Examples:

Setting up an event to 2 seconds after the scene has started.


class ExampleScene

  draws :title

  after 2.seconds do
    transition_to :next_scene
  end
end


132
133
134
# File 'lib/metro/scene.rb', line 132

def self.after(ticks,&block)
  after_intervals.push AfterIntervalFactory.new ticks, &block
end

.after_intervalsObject

The class defined updaters which will be converted to instance updaters when the scene has started.



357
358
359
# File 'lib/metro/scene.rb', line 357

def self.after_intervals
  @after_intervals ||= []
end

.hierarchyObject

Returns an array of all the scene names of all the ancestor scenes.

Returns:

  • an array of all the scene names of all the ancestor scenes



299
300
301
# File 'lib/metro/scene.rb', line 299

def self.hierarchy
  ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
end

.inherited(base) ⇒ Object

Captures all classes that subclass Scene.



330
331
332
333
# File 'lib/metro/scene.rb', line 330

def self.inherited(base)
  scenes << base.to_s
  Scenes.add(base)
end

.metro_nameObject

Returns a common name that can be used through the system as a common identifier.

Returns:

  • a common name that can be used through the system as a common identifier.



292
293
294
# File 'lib/metro/scene.rb', line 292

def self.metro_name
  scene_name
end

.scene_name(scene_name = nil) ⇒ Object

Allows you to set or retrieve the scene name for the Scene.

Examples:

Retrieving the default scene name


class ExampleScene < GameScene
end

ExampleScene.scene_name # => "example"

Setting a custom name for the Scene


class RollingCreditsScene < GameScene
  scene_name "credits"
end

RollingCreditsScene.scene_name # => "credits"

Parameters:

  • scene_name (String) (defaults to: nil)

    when specified it will set the scene name for the class to the value specified.

Returns:

  • the String name of the scene which it can be used as a reference for transitioning or for generating the appropriate view information.



277
278
279
280
281
282
283
284
285
286
287
# File 'lib/metro/scene.rb', line 277

def self.scene_name(scene_name=nil)
  @scene_name ||= begin
    if to_s == "Metro::Scene"
      to_s.underscore
    else
      to_s.gsub(/_?Scene$/i,'').underscore
    end
  end

  scene_name ? @scene_name = scene_name.to_s : @scene_name
end

.scenesObject

All subclasses of Scene, this should be all the defined scenes within the game.

Returns:

  • an Array of Scene subclasses



340
341
342
# File 'lib/metro/scene.rb', line 340

def self.scenes
  @scenes ||= []
end

Instance Method Details

#_prepare_transition(new_scene) ⇒ Object

Before a scene is transitioned away from to a new scene, this private method is here to allow for any housekeeping or other work that needs to be done before calling the subclasses implementation of ‘prepare_transition`.

Parameters:

  • new_scene (Scene)

    this is the instance of the scene that is about to replace the current scene.



425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/metro/scene.rb', line 425

def _prepare_transition(new_scene)
  log.debug "Preparing to transition from scene #{self} to #{new_scene}"

  new_scene.class.actors.find_all {|actor_factory| actor_factory.load_from_previous_scene? }.each do |actor_factory|
    new_actor = new_scene.actor(actor_factory.name)
    current_actor = actor(actor_factory.name)
    new_actor._load current_actor._save
  end

  prepare_transition_to(new_scene)
  new_scene.prepare_transition_from(self)
end

#actor(actor_or_actor_name) ⇒ Object

When an actor is defined, through the class method ‘draw` a getter and setter method is defined. However, it is a better interface internally not to rely heavily on send and have this small amount of obfuscation in the event that this needs to change.

Returns:

  • the actor with the given name.



91
92
93
94
95
96
97
# File 'lib/metro/scene.rb', line 91

def actor(actor_or_actor_name)
  if actor_or_actor_name.is_a? String or actor_or_actor_name.is_a? Symbol
    send(actor_or_actor_name)
  else
    actor_or_actor_name
  end
end

#add_actors_to_sceneObject



171
172
173
174
175
176
177
# File 'lib/metro/scene.rb', line 171

def add_actors_to_scene
  self.class.actors.each do |scene_actor|
    actor_instance = scene_actor.create
    actor_instance.scene = self
    send "#{scene_actor.name}=", actor_instance
  end
end

#after(ticks, &block) ⇒ Object

Perform an operation after the specified interval.

class ExampleScene

  draws :player

  def update
    if player.is_dead?
      after 2.seconds do
        transition_to :game_over
      end
    end
  end

end


153
154
155
156
157
# File 'lib/metro/scene.rb', line 153

def after(ticks,&block)
  tick = OnUpdateOperation.new interval: ticks, context: self
  tick.on_complete(&block)
  enqueue tick
end

#after_initializeObject

Note:

This method should be implemented in the Scene subclass.

As Scene does a lot of work for you with regarding to setting up content, it is best not to override #initialize and instead define an #after_initialize method within the subclasses of Scene.



34
# File 'lib/metro/scene.rb', line 34

def after_initialize ; end

#base_drawObject

The ‘base_draw` method is called by the Game Window. This is to allow for any special drawing needs to be handled before calling the traditional `draw` method defined in the subclassed Scene.



394
395
396
397
398
# File 'lib/metro/scene.rb', line 394

def base_draw
  drawers.each { |drawer| drawer.draw }
  draw
  drawers.reject! { |drawer| drawer.draw_completed? }
end

#base_updateObject

The ‘base_update` method is called by the Game Window. This is to allow for any special update needs to be handled before calling the traditional `update` method defined in the subclassed Scene.



375
376
377
378
379
# File 'lib/metro/scene.rb', line 375

def base_update
  updaters.each { |updater| updater.update }
  update
  updaters.reject! { |updater| updater.update_completed? }
end

#drawObject

Note:

This method should be implemented in the Scene subclass.

This is called after every #update and when the OS wants the window to repaint itself.



56
# File 'lib/metro/scene.rb', line 56

def draw ; end

#drawersObject

The objects that need to be drawn with every draw cycle. These objects are traditionally the model objects, like the actors defined within the scene.



385
386
387
# File 'lib/metro/scene.rb', line 385

def drawers
  @drawers ||= []
end

#enqueue(updater) ⇒ Object

Enqueue will add an updater to the list of updaters that are run initially when update is called. An updater is any object that can respond to #update. This is used for animations.



349
350
351
# File 'lib/metro/scene.rb', line 349

def enqueue(updater)
  updaters.push(updater)
end

#notification(event, sender = nil) ⇒ Object

Post a custom notification event. This will trigger an event for all the objects that are registered for notification with the current state.



103
104
105
106
# File 'lib/metro/scene.rb', line 103

def notification(event,sender=nil)
  sender = sender || UnknownSender
  state.fire_events_for_notification(event,sender)
end

#prepare_transition_from(old_scene) ⇒ Object

Note:

This method should be implemented in the Scene subclass.

Before a scene is transitioned to it is called with the previous scene. This allows for the new scene to retrieve any data from the previous scene to assist with the layout of the current scene.

Parameters:

  • old_scene (Scene)

    this is the instance of the scene that is being moved away from.



80
# File 'lib/metro/scene.rb', line 80

def prepare_transition_from(old_scene) ; end

#prepare_transition_to(new_scene) ⇒ Object

Note:

This method should be implemented in the Scene subclass.

Before a scene is transitioned away from to a new scene, this method is called to allow for the scene to complete any tasks, stop any actions, or pass any information from the existing scene to the scene that is about to replace it.

Parameters:

  • new_scene (Scene)

    this is the instance of the scene that is about to replace the current scene.



68
# File 'lib/metro/scene.rb', line 68

def prepare_transition_to(new_scene) ; end

#register_actor(actor_factory) ⇒ Object

Registering an actor involves setting up the actor within the window, adding them to the list of things that need to be drawn and then registering any eventst that they might have.



242
243
244
245
246
247
248
249
250
251
# File 'lib/metro/scene.rb', line 242

def register_actor(actor_factory)
  registering_actor = actor(actor_factory.name)
  registering_actor.window = window
  registering_actor.show

  drawers.push(registering_actor)
  updaters.push(registering_actor)

  register_events_for_target(registering_actor,registering_actor.class.events)
end

#register_actors!Object

Register all the actors that were defined for this scene.



218
219
220
# File 'lib/metro/scene.rb', line 218

def register_actors!
  self.class.actors.each { |actor| register_actor(actor) }
end

#register_after_intervals!Object



231
232
233
234
235
# File 'lib/metro/scene.rb', line 231

def register_after_intervals!
  self.class.after_intervals.each do |after_interval|
    after after_interval.ticks, &after_interval.block
  end
end

#register_animations!Object

Register all the animations that were defined for this scene.



225
226
227
228
229
# File 'lib/metro/scene.rb', line 225

def register_animations!
  self.class.animations.each do |animation|
    animate animation.actor, animation.options, &animation.on_complete_block
  end
end

#register_events!Object

Register all the events that were defined for this scene.



211
212
213
# File 'lib/metro/scene.rb', line 211

def register_events!
  register_events_for_target(self,self.class.events)
end

#register_events_for_target(target, events) ⇒ Object

Helper method that is used internally to setup the events for the specified target.

Parameters:

  • target (Object)

    the intended target for the specified events. This object will have the appropriate methods and functionality to respond appropriately to the action blocks defined in the methods.

  • events (Array<EventFactory>)

    an array of EventFactory objects that need to now be mapped to the specified target.



448
449
450
# File 'lib/metro/scene.rb', line 448

def register_events_for_target(target,events)
  state.add_events_for_target(target,events)
end

#scene_nameObject

Allows you to set or retrieve the scene name for the Scene.

Examples:

Retrieving the default scene name


class ExampleScene
  def show
    puts "Showing Scene: #{self.scene_name}" # => Showing Scene: example
  end
end

Returns:

  • the string name of the Scene.



316
317
318
# File 'lib/metro/scene.rb', line 316

def scene_name
  self.class.scene_name
end

#showObject

Note:

This method should be implemented in the Scene subclass.

This method is called right after the scene has been adopted by the window



41
# File 'lib/metro/scene.rb', line 41

def show ; end

#stateObject

The event state manager is configured through the #events method, which stores all the gamepad and keyboard events defined. By default a scene is placed in the default state and events that are added to this basic state.

See Also:

  • Events


459
460
461
# File 'lib/metro/scene.rb', line 459

def state
  @event_state_manager ||= EventStateManager.new
end

#to_hashObject

A Scene represented as a hash currently only contains the drawers

Returns:

  • a hash of all the drawers



468
469
470
471
472
473
474
475
# File 'lib/metro/scene.rb', line 468

def to_hash
  drawn = drawers.find_all{|draw| draw.saveable_to_view }.inject({}) do |hash,drawer|
    drawer_hash = drawer.to_hash
    hash.merge drawer_hash
  end

  drawn
end

#to_sObject

Returns the string representation of a scene, this is used for debugging.

Returns:

  • the string representation of a scene, this is used for debugging.



323
324
325
# File 'lib/metro/scene.rb', line 323

def to_s
  "[SCENE: #{self.class.scene_name}(#{self.class})]"
end

#transition_to(scene_or_scene_name, options = {}) ⇒ Object

‘transition_to` performs the work of transitioning this scene to another scene.

Parameters:

  • scene_or_scene_name (String, Symbol, Object)

    the name of the Scene which can be either the class or a string/symbol representation of the shortened scene name. This could also be an instance of scene.



411
412
413
414
415
# File 'lib/metro/scene.rb', line 411

def transition_to(scene_or_scene_name,options = {})
  new_scene = Scenes.generate(scene_or_scene_name,options)
  _prepare_transition(new_scene)
  window.scene = new_scene
end

#updateObject

Note:

This method should be implemented in the Scene subclass.

This is called every update interval while the window is being shown.



48
# File 'lib/metro/scene.rb', line 48

def update ; end

#updatersObject

The objects that need to be executed on every update. These objects are traditionally animations or window events for held pressed buttons. But can be any objects that responds to the method #update.



366
367
368
# File 'lib/metro/scene.rb', line 366

def updaters
  @updaters ||= []
end