Skip to content
Michael Fairley edited this page Sep 1, 2013 · 12 revisions

Scene

A scene is one of three major concepts in Metro. A scene represents screens, transitions, or stages within the game. A Scene itself coordinates the many actors, events, animations, and actions that are currently on screen.

Overview

A Scene is similar to a Rails Controller.

Scenes are stored in the 'scenes' directory. The template game that Metro generates provides you with several scenes which are subclasses of GameScene. GameScene is a subclass of Metro::Scene. All scenes within Metro must have Metro::Scene as an ancestor.

This is again very similar to how Rails will generate a controller named ApplicationController and all new controllers will be subclasses of it.

An important suggestion is to use the inheritance with care. It is often times much easier to manage inheritance that is wide and shallow (e.g. Lots of subclasses of GameScene) instead of deep.

Creating a Scene

Scenes are not required to reside in the scenes directory. However, it is strongly encouraged to maintain the organization of your code.

Many scenes may also share a single file. However, it is strongly encouraged that you maintain one scene per file.

Manual Creation

A new scene can be created manually simply by saving ruby code that defines a scene to a file.

class DungeonScene < GameScene

end
  • Scene classes often use a common naming convention. Selecting a unique name as a prefix and the word Scene as a suffix. In the above example the word 'Dungeon' is the unique name.

  • The name of the file often matches the scene class name. Except the file name is usually a snake cased version of the CamelCased class name. This is a common convention within Ruby.

Generator

The metro command-line tool provides a generator to help create a new scene that abides by the conventions defined above.

$ metro generate scene new DungeonScene
$ metro generate scene new dungeon_scene
$ metro generate scene new dungeon

Any of the above specified commands will generate the a file at the path scenes/dungeon_scene.rb which contains a class named DungeonScene.

Scene Name

Each scene has a name. By default the name of a scene is a snaked cased version of the unique name prefix of the scene class.

The scene name of the the previously example is dungeon:

class FirstMazeScene < GameScene ; end

The following scene name would first_maze.

Scene names are used throughout your game as references to scenes to prevent the spread of scene classes spread all throughout the code.

  • The first scene of your game that is loaded, specified in your game configuration, uses the name of the scene.

  • The scene name, by default, determines the default view file that it uses.

  • Scene Transitions take the scene name as a parameter.

The name of a scene can be overridden. A custom scene name can be explicitly defined.

The following example defines a custom scene name, which overrides the usual default:

class FirstMazeScene < GameScene
  scene_name :first_labyrinth
end

Methods

A scene has a series of events which are essential to the lifetime of the scene. These methods are defined as placeholder methods in the Scene superclass. This allows you to redefine only the necessary methods in your scene.

This method is executed immediately after the initial initialize code is completed. A scene, however, is not yet visible and does not yet have the to draw, calculate layouts, or access any model object that requires the use of the window.

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.

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

This is often the method where you have access to all available resources. This is an ideal location for you to complete any initialize that requires model objects to establish relationships with each other, start playing music, or for models to generate or create any necessary sub-models.

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

This is the method where you would define your core game logic that needs to happen on each update.

base_update is actually called first, which in turn calls update. This is done so that Metro can perform automatically perform the update operations for animations or existing models defined in the scene. If you need to override all existing behavior, you may want to redefine base_update.

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

This is the method where you would define any custom drawing code that happens in your scene.

base_draw is actually called first, which in turn calls draw. This is done so that Metro can perform automatic drawing of existing models defined in the scene. If you need to override all existing behavior, you may want to redefine base_draw.

This is called during a scene transition event. After the scene transition event has been initiated, this method will be called for the current scene. This happens immediately before prepare_transition_to(old_scene) is called.

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 new scene that is about to replace it. The new_scene parameter is the scene that is about to replace the existing scene.

This is called during a scene transition event. This is called immediately following the call to prepare_transition_to(new_scene).

The new scene, which is about to replace the current scene, is the receiver of this call. Before this scene is transitioned to the current visible scene is passed to this new scene. This allows for the new scene to retrieve any data from the previous scene to assist with the layout of the current scene.

A scene is able to respond to events. These events could be generated from keyboard, mouse, or gamepad input. They may also be custom notifications generated by other models within the current scene.

A scene's ability to register and respond to events is because a Scene includes the module HasEvents which extends the ClassMethods.

Defining Models

A scene has a number of helper methods (draw, draws, and play) that allow you to quickly add models within the scene.

A scene's ability to register models is because a Scene includes the model Draws which extends the ClassMethods.

The draw class method within a scene allows you to define a model to draw. This instance of the model is often referred to an as an actor. The definition within a scene is simply a hash which contains all the parameters you wish to define.

class HellScene < GameScene

  draw :title, model: 'metro::ui::label',
    text: 'Welcome To Hell!',
    position: "320,240,0",
    color: "rgba(255,255,255,1.0)"

end

The first parameter is the name of actor. The hash of parameters that follow the actor name describe important characteristics about what model the actor is based on and the important details of that should be presented.

  • model is one of the core models provided with Metro.
  • text is the text that appears within the label.
  • position describes the location of the upper-left point of the label.
  • color is the color represented as a web color string.

By stating that this scene draws the following 'metro::ui::label' it will automatically add this actor, in the update loop and draw loop. A 'metro::ui::label' is a simple model so it performs no action when its update method is called. It does love to draw itself and will generate text to the screen which reads 'Welcome To Hell!'.

Optional Model Parameter

If you do not provide a model, Metro will try to match the name of the actor against the names of all the models that it knows. In the following case a hero is drawn with the Hero model:

class HellScene < GameScene
  draw :hero
end

class Hero < Metro::Model
  # details that define a hero
end

The play class method within a scene allows you to define song. This is similar to the draw class method, except it is assumed that you are creating a 'metro::audio::song' so you do not specify a model.

class HellScene < GameScene
  play :theme, song: 'title.ogg', volume: 0.2
end

This is functionally equivalent to defining it with the draw method:

class HellScene < GameScene
  draw :theme, model: 'metro::audio::song', song: 'title.ogg', volume: 0.2
end

Using a View to define your Models

By default your Scene automatically has an associated view file based on the name of the scene. The name of a scene's view can also be overridden.

The view file allows you to define numerous actor details in another location.

Previously we defined the 'Hell' Scene which defined a title label with a lovely welcome message.

class HellScene < GameScene

  draw :title, model: 'metro::ui::label',
    text: 'Welcome To Hell!',
    position: "320,240,0",
    color: "rgba(255,255,255,1.0)"

end

We can also move this content to the Hell Scene's view file hell.yaml:

title:
  model: metro::ui::label
  text: Welcome To Hell!
  position: "320,240,0"
  color: "rgba(255,255,255,1.0)"

We can redefine our Hell Scene more succinctly:

class HellScene < GameScene
  draw :title
end
  • Parameters, for an actor, can be defined in both the scene and the view
  • Parameters defined for an the actor, within the scene, will override the parameters defined for an actor in the view.

The draws class method within a scene allows you to define a list of actor names that will be drawn in the scene. Actors defined in this list cannot have any parameters specified.

This is a helpful method if you want to define a large number of actors which share names with models or actors that have their details already defined in the view.

A scene has a number of helper methods (animate and change) that allow you to quickly add animations within your scene.

A scene's ability to register animations is because a Scene includes the model HasAnimations which extends the ClassMethods.

animate / change (class methods)

A scene can define an animate or change method at the class level. animate and change are identical to each other. Defining an animation or change at the class level defines an animation which will be added to list of objects that are called during the scene's update process. The animation or change defined at the class level will begin updating when update for the scene is called for the first time.

Using the same scene we defined our previous example, here we will fade the title to transparent over 120 game ticks when the scene starts.

class HellScene < GameScene

  draws :title

  animate :title, to: { alpha: 0 }, interval: 120.ticks do
    puts "Title is now faded."
  end
end

This could have also been written with change:

class HellScene < GameScene

  draws :title

  change :title, to: { alpha: 0 }, interval: 120.ticks do
    puts "Title is now faded."
  end
end

animate / change (instance methods)

A scene can send the animate or change method in a method within a Scene, within the block of an event, or within the block of an animation or change. animate and change are identical to each other. Defining an animation or change at the instance level defines an animation which will be added to list of objects that are called during the scene's update process. The animation or change defined within a method will begin to update during the scene's next update call.

In our previous example we faded out the title. When that is finished, it is time to turn up the volume of the background music over 180 game ticks.

class HellScene < GameScene

  draws :title
  play :theme, song: 'title.ogg', volume: 0.0, state: 'stop'

  animate :title, to: { alpha: 0 }, interval: 120.ticks do
    change :theme, to { volume: 1.0 }, interval: 180.ticks
  end
end

after

A scene defines both a class method and an instance method that allow you to process or perform an event after the specified interval has passed. This is a useful tool when coupled with animations.

Often times you will want to delay an animation or change effect. This can be done with the after class method.

In our previous example we immediately faded out our title. The effect was what we hoped to accomplish. The only problem is that it happened too soon after the scene started.

class HellScene < GameScene

  draws :title

  after 2.seconds do
    change :title, to: { alpha: 0 }, interval: 120.ticks do
      change :theme, to { volume: 1.0 }, interval: 180.ticks
    end
  end
end

The sample game generated by Metro includes a helper method within GameScene named fade_in_and_out. This method is utilizes animate and after to generate a fade in and fade out effect for text to the screen.

class GameScene < Metro::Scene

  def fade_in_and_out(name)
    animate name, to: { alpha: 255, background_color_alpha: 20 }, interval: 2.seconds do
      after 1.second do
        animate name, to: { alpha: 0, background_color_alpha: 0 }, interval: 1.second do
          yield if block_given?
        end
      end
    end
  end

end

This allows for the ability to easily fade in previously hidden actors (i.e. alpha is 0) and then fade them out after 1 second. The additional yield is provided if several messages want to be faded in and out in a series.