metro-ld25 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +12 -0
  6. data/Guardfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +189 -0
  9. data/Rakefile +18 -0
  10. data/bin/metro +16 -0
  11. data/changelog.md +157 -0
  12. data/lib/assets/menu-movement.wav +0 -0
  13. data/lib/assets/menu-selection.wav +0 -0
  14. data/lib/assets/missing.ogg +0 -0
  15. data/lib/assets/missing.png +0 -0
  16. data/lib/assets/missing.wav +0 -0
  17. data/lib/assets/missing_animation.png +0 -0
  18. data/lib/commands/generate_game.rb +13 -0
  19. data/lib/commands/generate_model.rb +25 -0
  20. data/lib/commands/generate_scene.rb +36 -0
  21. data/lib/commands/generate_view.rb +21 -0
  22. data/lib/commands/thor.rb +83 -0
  23. data/lib/core_ext/class.rb +14 -0
  24. data/lib/core_ext/numeric.rb +59 -0
  25. data/lib/gosu_ext/color.rb +62 -0
  26. data/lib/gosu_ext/gosu_constants.rb +53 -0
  27. data/lib/locale/en.yml +35 -0
  28. data/lib/locale/locale.rb +1 -0
  29. data/lib/metro.rb +140 -0
  30. data/lib/metro/animation.rb +135 -0
  31. data/lib/metro/animation/after_interval_factory.rb +12 -0
  32. data/lib/metro/animation/animation_factory.rb +15 -0
  33. data/lib/metro/animation/easing/ease_in.rb +15 -0
  34. data/lib/metro/animation/easing/easing.rb +51 -0
  35. data/lib/metro/animation/easing/linear.rb +15 -0
  36. data/lib/metro/animation/has_animations.rb +70 -0
  37. data/lib/metro/animation/implicit_animation.rb +100 -0
  38. data/lib/metro/animation/on_update_operation.rb +96 -0
  39. data/lib/metro/animation/scene_animation.rb +16 -0
  40. data/lib/metro/asset_path.rb +97 -0
  41. data/lib/metro/events/control_definition.rb +11 -0
  42. data/lib/metro/events/controls.rb +42 -0
  43. data/lib/metro/events/event_data.rb +60 -0
  44. data/lib/metro/events/event_dictionary.rb +52 -0
  45. data/lib/metro/events/event_factory.rb +17 -0
  46. data/lib/metro/events/event_relay.rb +300 -0
  47. data/lib/metro/events/event_state_manager.rb +63 -0
  48. data/lib/metro/events/events.rb +3 -0
  49. data/lib/metro/events/has_events.rb +108 -0
  50. data/lib/metro/events/hit_list.rb +75 -0
  51. data/lib/metro/events/unknown_sender.rb +5 -0
  52. data/lib/metro/font.rb +69 -0
  53. data/lib/metro/game.rb +102 -0
  54. data/lib/metro/game/dsl.rb +68 -0
  55. data/lib/metro/image.rb +68 -0
  56. data/lib/metro/logging.rb +33 -0
  57. data/lib/metro/missing_scene.rb +21 -0
  58. data/lib/metro/models/audio/song.rb +33 -0
  59. data/lib/metro/models/draws.rb +86 -0
  60. data/lib/metro/models/key_value_coding.rb +38 -0
  61. data/lib/metro/models/model.rb +236 -0
  62. data/lib/metro/models/model_factory.rb +32 -0
  63. data/lib/metro/models/models.rb +62 -0
  64. data/lib/metro/models/properties/animation_property.rb +115 -0
  65. data/lib/metro/models/properties/array_property.rb +24 -0
  66. data/lib/metro/models/properties/boolean_property.rb +27 -0
  67. data/lib/metro/models/properties/color_property.rb +116 -0
  68. data/lib/metro/models/properties/dimensions_property.rb +84 -0
  69. data/lib/metro/models/properties/font_property.rb +130 -0
  70. data/lib/metro/models/properties/image_property.rb +96 -0
  71. data/lib/metro/models/properties/model_property.rb +84 -0
  72. data/lib/metro/models/properties/numeric_property.rb +29 -0
  73. data/lib/metro/models/properties/options_property/no_option.rb +29 -0
  74. data/lib/metro/models/properties/options_property/options.rb +94 -0
  75. data/lib/metro/models/properties/options_property/options_property.rb +125 -0
  76. data/lib/metro/models/properties/position_property.rb +90 -0
  77. data/lib/metro/models/properties/property.rb +221 -0
  78. data/lib/metro/models/properties/property_owner.rb +137 -0
  79. data/lib/metro/models/properties/sample_property.rb +84 -0
  80. data/lib/metro/models/properties/scale_property.rb +80 -0
  81. data/lib/metro/models/properties/song_property.rb +89 -0
  82. data/lib/metro/models/properties/text_property.rb +75 -0
  83. data/lib/metro/models/ui/animated_sprite.rb +85 -0
  84. data/lib/metro/models/ui/border.rb +95 -0
  85. data/lib/metro/models/ui/fps.rb +54 -0
  86. data/lib/metro/models/ui/generic.rb +66 -0
  87. data/lib/metro/models/ui/grid_drawer.rb +74 -0
  88. data/lib/metro/models/ui/image.rb +87 -0
  89. data/lib/metro/models/ui/label.rb +175 -0
  90. data/lib/metro/models/ui/menu.rb +214 -0
  91. data/lib/metro/models/ui/model_label.rb +65 -0
  92. data/lib/metro/models/ui/model_labeler.rb +79 -0
  93. data/lib/metro/models/ui/rectangle.rb +59 -0
  94. data/lib/metro/models/ui/sprite.rb +79 -0
  95. data/lib/metro/models/ui/tile_map.rb +162 -0
  96. data/lib/metro/models/ui/ui.rb +13 -0
  97. data/lib/metro/parameters/command_line_args_parser.rb +68 -0
  98. data/lib/metro/parameters/options.rb +25 -0
  99. data/lib/metro/parameters/parameters.rb +2 -0
  100. data/lib/metro/sample.rb +40 -0
  101. data/lib/metro/scene.rb +477 -0
  102. data/lib/metro/scenes.rb +154 -0
  103. data/lib/metro/song.rb +56 -0
  104. data/lib/metro/template_message.rb +60 -0
  105. data/lib/metro/transitions/edit_transition_scene.rb +100 -0
  106. data/lib/metro/transitions/fade_transition_scene.rb +66 -0
  107. data/lib/metro/transitions/scene_transitions.rb +44 -0
  108. data/lib/metro/transitions/transition_scene.rb +19 -0
  109. data/lib/metro/units/bounds.rb +8 -0
  110. data/lib/metro/units/calculation_validations.rb +74 -0
  111. data/lib/metro/units/dimensions.rb +60 -0
  112. data/lib/metro/units/point.rb +51 -0
  113. data/lib/metro/units/rectangle_bounds.rb +85 -0
  114. data/lib/metro/units/scale.rb +46 -0
  115. data/lib/metro/units/units.rb +6 -0
  116. data/lib/metro/version.rb +32 -0
  117. data/lib/metro/views/json_view.rb +60 -0
  118. data/lib/metro/views/no_view.rb +34 -0
  119. data/lib/metro/views/parsers.rb +42 -0
  120. data/lib/metro/views/scene_view.rb +107 -0
  121. data/lib/metro/views/view.rb +133 -0
  122. data/lib/metro/views/writers.rb +43 -0
  123. data/lib/metro/views/yaml_view.rb +94 -0
  124. data/lib/metro/window.rb +94 -0
  125. data/lib/setup_handlers/exit_if_dry_run.rb +26 -0
  126. data/lib/setup_handlers/game_execution.rb +65 -0
  127. data/lib/setup_handlers/load_game_configuration.rb +65 -0
  128. data/lib/setup_handlers/load_game_files.rb +101 -0
  129. data/lib/setup_handlers/move_to_game_directory.rb +25 -0
  130. data/lib/setup_handlers/reload_game_on_game_file_changes.rb +79 -0
  131. data/lib/templates/game/README.md.tt +52 -0
  132. data/lib/templates/game/assets/brand.jpg +0 -0
  133. data/lib/templates/game/assets/hero.png +0 -0
  134. data/lib/templates/game/lib/custom_easing.rb +32 -0
  135. data/lib/templates/game/metro.tt +63 -0
  136. data/lib/templates/game/models/hero.rb +62 -0
  137. data/lib/templates/game/scenes/brand_scene.rb +19 -0
  138. data/lib/templates/game/scenes/brand_to_title_scene.rb +13 -0
  139. data/lib/templates/game/scenes/first_scene.rb +28 -0
  140. data/lib/templates/game/scenes/game_scene.rb +43 -0
  141. data/lib/templates/game/scenes/title_scene.rb +15 -0
  142. data/lib/templates/game/views/brand.yaml +4 -0
  143. data/lib/templates/game/views/brand_to_title.yaml +8 -0
  144. data/lib/templates/game/views/first.yaml +26 -0
  145. data/lib/templates/game/views/title.yaml +11 -0
  146. data/lib/templates/message.erb +23 -0
  147. data/lib/templates/model.rb.tt +111 -0
  148. data/lib/templates/scene.rb.tt +140 -0
  149. data/lib/templates/view.yaml.tt +11 -0
  150. data/lib/tmxed_ext/tile_set.rb +34 -0
  151. data/metro.gemspec +56 -0
  152. data/spec/core_ext/numeric_spec.rb +78 -0
  153. data/spec/core_ext/string_spec.rb +33 -0
  154. data/spec/gosu_ext/color_spec.rb +80 -0
  155. data/spec/metro/events/event_state_manager_spec.rb +5 -0
  156. data/spec/metro/models/key_value_coding_spec.rb +61 -0
  157. data/spec/metro/models/properties/array_property_spec.rb +60 -0
  158. data/spec/metro/models/properties/color_property_spec.rb +85 -0
  159. data/spec/metro/models/properties/dimensions_spec.rb +29 -0
  160. data/spec/metro/models/properties/font_property_spec.rb +127 -0
  161. data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
  162. data/spec/metro/models/properties/options_property/no_option_spec.rb +25 -0
  163. data/spec/metro/models/properties/options_property/options_property_spec.rb +133 -0
  164. data/spec/metro/models/properties/options_property/options_spec.rb +125 -0
  165. data/spec/metro/models/properties/position_property_spec.rb +90 -0
  166. data/spec/metro/models/ui/label_spec.rb +259 -0
  167. data/spec/metro/parameters/command_line_args_parser_spec.rb +42 -0
  168. data/spec/metro/scene_spec.rb +15 -0
  169. data/spec/metro/scene_views/json_view_spec.rb +27 -0
  170. data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
  171. data/spec/metro/scenes_spec.rb +77 -0
  172. data/spec/metro/units/point_spec.rb +132 -0
  173. data/spec/metro/views/view_spec.rb +53 -0
  174. data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
  175. data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
  176. data/spec/spec_helper.rb +20 -0
  177. metadata +374 -0
@@ -0,0 +1,68 @@
1
+ module Metro
2
+
3
+ #
4
+ # Image is a wrapper class for a Gosu Image. This allows for additional data
5
+ # to be stored without relying on monkey-patching on functionality.
6
+ #
7
+ class Image < SimpleDelegator
8
+
9
+ def initialize(gosu_image,path,tileable)
10
+ super(gosu_image)
11
+ @path = path
12
+ @tileable = tileable
13
+ end
14
+
15
+ # The relative path of the image
16
+ attr_reader :path
17
+
18
+ # The tileability of the image
19
+ attr_reader :tileable
20
+
21
+ def dimensions
22
+ Metro::Units::Dimensions.of width, height
23
+ end
24
+
25
+ #
26
+ # Finds an existing image or creates a new image given the window, path,
27
+ # and tileablilty.
28
+ #
29
+ # @example Finding or creating an Image
30
+ #
31
+ # Metro::Image.find_or_create window: model.window,
32
+ # path: "asset_path", tileable: tileable
33
+ #
34
+ def self.find_or_create(options)
35
+ path = AssetPath.with(options[:path])
36
+ images[path.to_s] or (images[path.to_s] = create(options))
37
+ end
38
+
39
+ #
40
+ # Create an image given the window, path, and tileability.
41
+ #
42
+ # @example Creating an Image
43
+ #
44
+ # Metro::Image.create window: model.window,
45
+ # path: "asset_path", tileable: tileable
46
+ #
47
+ def self.create(options)
48
+ window, asset_path, tileable = create_params(options)
49
+ gosu_image = Gosu::Image.new(window,asset_path.filepath,tileable)
50
+ new gosu_image, asset_path.path, tileable
51
+ end
52
+
53
+ private
54
+
55
+ def self.create_params(options)
56
+ options.symbolize_keys!
57
+ asset_path = AssetPath.with(options[:path])
58
+ window = options[:window]
59
+ tileable = !!options[:tileable]
60
+ [ window, asset_path, tileable ]
61
+ end
62
+
63
+ def self.images
64
+ @images ||= {}
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,33 @@
1
+
2
+ #
3
+ # Generates a default logger to standard out that can be used within Metro or the game.
4
+ #
5
+ # @example Outputting information at the debug level
6
+ #
7
+ # log.debug "The the screen resolution is #{Game.width},#{Game.height}"
8
+ #
9
+ def log
10
+ @log ||= begin
11
+ logger = Logger.new(STDOUT)
12
+ logger.level = Logger::DEBUG
13
+ logger
14
+ end
15
+ end
16
+
17
+ #
18
+ # Display an error message defined within the localization file. A game error displays
19
+ # a error title, message, and actions that can be taken to possibly address this issue.
20
+ #
21
+ # @param [String] message the I18n string found in the locale file.
22
+ # @param [Hash] details contains all the possible key-value pairs that might be needed
23
+ # for the localized error messages.
24
+ #
25
+ def error!(messages, details = {})
26
+ details = { show: true, exit: true }.merge details
27
+
28
+ message = TemplateMessage.new messages: messages, details: details,
29
+ website: Game.website, contact: Game.contact
30
+
31
+ warn message if details[:show]
32
+ exit 1 if details[:exit]
33
+ end
@@ -0,0 +1,21 @@
1
+ module Metro
2
+ class MissingScene < Scene
3
+ scene_name :missing_scene
4
+
5
+ class << self
6
+ attr_accessor :missing_scene
7
+ end
8
+
9
+ draw :title, text: "Missing Scene!",
10
+ position: "20,20,1",
11
+ color: "rgb(255,0,0)",
12
+ font: {size: 80},
13
+ model: "metro::ui::label"
14
+
15
+ draw :message, text: 'The scene `#{self.class.missing_scene}` was requested, but is missing!',
16
+ position: "20,100,1",
17
+ color: "rgb(255,255,255)",
18
+ model: "metro::ui::label"
19
+
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module Metro
2
+ module Audio
3
+
4
+ #
5
+ # A song represents an audio representation.
6
+ #
7
+ class Song < Metro::Model
8
+
9
+ property :song
10
+ property :volume, default: 1.0
11
+ property :state, type: :text, default: 'play'
12
+
13
+ def show
14
+ song.volume = self.volume
15
+ play if state == "play"
16
+ end
17
+
18
+ def stop
19
+ song.stop
20
+ end
21
+
22
+ def play
23
+ song.play if not song.playing? and not song.paused?
24
+ end
25
+
26
+ def pause
27
+ song.playing? ? song.pause : song.play
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,86 @@
1
+ require_relative 'model_factory'
2
+
3
+ module Metro
4
+ module Draws
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ #
13
+ # Define an actor with the given name and options.
14
+ #
15
+ # As a convenience the draw method will define `getter` and `setter`
16
+ # methods for the specified actor.
17
+ #
18
+ # @example Defining a title label within a scene
19
+ #
20
+ # class ExampleScene
21
+ # draw :title, text: 'Title Screen',
22
+ # model: 'metro::ui::label'
23
+ # position: '20,20,0',
24
+ # scale: '3,3',
25
+ # color: 'rgba(255,255,255,1.0)'
26
+ #
27
+ # def show
28
+ # puts "Where is my title? #{title.x},#{title.y}"
29
+ # end
30
+ # end
31
+ #
32
+ def draw(actor_name,options = {})
33
+
34
+ view_content_for_actor = view.content[actor_name.to_s]
35
+
36
+ actor_data = view_content_for_actor.merge(options)
37
+ actor_data[:name] = actor_name
38
+
39
+ scene_actor = ModelFactory.new actor_name, actor_data
40
+
41
+ define_method actor_name do
42
+ instance_variable_get("@#{actor_name}")
43
+ end
44
+
45
+ define_method "#{actor_name}=" do |value|
46
+ instance_variable_set("@#{actor_name}",value)
47
+ end
48
+
49
+ drawings.push scene_actor
50
+ end
51
+
52
+ #
53
+ # Define a sound actor with the given anem and options.
54
+ #
55
+ # @see #draw
56
+ #
57
+ def play(song_name,options={})
58
+ draw song_name, options.merge(model: "metro::audio::song")
59
+ end
60
+
61
+ #
62
+ # Define several actors to be drawn.
63
+ #
64
+ def draws(*actor_names)
65
+ actor_names = actor_names.flatten.compact
66
+
67
+ actor_names.each do |actor_name|
68
+ draw actor_name
69
+ end
70
+
71
+ drawings
72
+ end
73
+
74
+ #
75
+ # All of the model factories that have been defined.
76
+ #
77
+ def drawings
78
+ @drawings ||= []
79
+ end
80
+
81
+ alias_method :actors, :drawings
82
+
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,38 @@
1
+ module Metro
2
+
3
+ #
4
+ # Key-Value coding emulates the functionality found in Objective-C, which allows
5
+ # for an object to be sent a message which contains the method to return. This is
6
+ # the same as Ruby. However, Objective-C also supports the use of the dot notation
7
+ # within the keys to acces the sub-values.
8
+ #
9
+ # @example Setting the red value of the color on a Model.
10
+ #
11
+ # class Elf
12
+ # include KeyValueCoding
13
+ #
14
+ # attr_accessor :color
15
+ # end
16
+ #
17
+ # elf = Elf.new
18
+ # elf.color = Gosu::Color.new "rgb(0,0,0)"
19
+ #
20
+ # elf.get("color.red") # => 0
21
+ # elf.set("color.red",255)
22
+ # elf.get("color.red") # => 255
23
+ #
24
+ module KeyValueCoding
25
+
26
+ def set(name,value)
27
+ keys = name.to_s.split('.')
28
+ key_to_set = keys[0..-2].inject(self) {|target,method| target.send(method) }
29
+ key_to_set.send("#{keys.last}=",value)
30
+ end
31
+
32
+ def get(name)
33
+ keys = name.to_s.split('.')
34
+ keys.inject(self) {|target,method| target.send(method) }
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,236 @@
1
+ require_relative 'key_value_coding'
2
+ require_relative 'properties/property'
3
+ require_relative 'models'
4
+
5
+ module Metro
6
+
7
+ #
8
+ # The Model is a basic, generic representation of a game object
9
+ # that has a visual representation within the scene's window.
10
+ #
11
+ # Model is designed to be an abstract class, to be subclassed by
12
+ # other models.
13
+ #
14
+ # @see Models::Generic
15
+ #
16
+ class Model
17
+ include PropertyOwner
18
+ include Units
19
+
20
+ #
21
+ # This is an entry point for customization. As the model's {#initialize}
22
+ # method performs may perform some initialization that may be necessary.
23
+ #
24
+ # At this point the model has been created. However, the window and scene
25
+ # of the model will not have been defined and defined properties rely on
26
+ # the window or scene will return nil values. Other properties also will
27
+ # likely not be set.
28
+ #
29
+ # @note This method should be implemented in the Model subclass.
30
+ #
31
+ def after_initialize ; end
32
+
33
+ #
34
+ # This is an entry point for customization. After the model's properties
35
+ # have been set and the model has been assigned to the window and scene
36
+ # this method is called. Here is where customization of properties or
37
+ # final positioning can be performed.
38
+ #
39
+ # @note This method may be implemented in the Model subclass.
40
+ #
41
+ def show ; end
42
+
43
+ #
44
+ # This is called every update interval while the actor is in the scene
45
+ #
46
+ # @note This method should be implemented in the Model subclass
47
+ #
48
+ def update ; end
49
+
50
+ #
51
+ # This is called after an update. A model normally is not removed after
52
+ # an update, however if the model responds true to #completed? then it
53
+ # will be removed.
54
+ #
55
+ # @note This method should be implemented in the Model sublclass if you
56
+ # are interested in having the model be removed from the scene.
57
+ #
58
+ def completed? ; false ; end
59
+
60
+ #
61
+ # This is called after every {#update} and when the OS wants the window to
62
+ # repaint itself.
63
+ #
64
+ # @note This method should be implemented in the Model subclass.
65
+ #
66
+ def draw ; end
67
+
68
+ def self.model_name(model_name=nil)
69
+ @model_name ||= to_s.underscore
70
+ model_name ? @model_name = model_name.to_s : @model_name
71
+ end
72
+
73
+ #
74
+ # @return [String] the name of the model class.
75
+ #
76
+ property :model, type: :text
77
+
78
+ #
79
+ # @return [String] the name of model as it is used within the view or the scene.
80
+ # This is the common name, the key within the view file, or the name symbol
81
+ # name specified in the scene.
82
+ #
83
+ property :name, type: :text
84
+
85
+ #
86
+ # @return [TrueClass,FalseClass] true if the model should be saved to the
87
+ # view file, false when the model should not be savedable to the view file.
88
+ #
89
+ property :saveable_to_view, type: :boolean, default: true
90
+
91
+ #
92
+ # The window that this model that this window is currently being
93
+ # displayed.
94
+ #
95
+ # The current value of window is managed by the scene
96
+ # as this is set when the Scene is added to the window. All the
97
+ # models gain access to the window.
98
+ #
99
+ # @see Window
100
+ #
101
+ attr_accessor :window
102
+
103
+ #
104
+ # The scene that this model is currently being displayed.
105
+ #
106
+ # The current value of scene is managed by the scene as this
107
+ # is set when the scene is created.
108
+ #
109
+ # @see Scene
110
+ attr_accessor :scene
111
+
112
+ include KeyValueCoding
113
+
114
+ #
115
+ # Generate a custom notification event with the given name.
116
+ #
117
+ # @param [Symbol] event the name of the notification to generate.
118
+ #
119
+ def notification(event)
120
+ scene.notification(event.to_sym,self)
121
+ end
122
+
123
+ #
124
+ # Allows for the definition of events within the scene.
125
+ #
126
+ include HasEvents
127
+
128
+ #
129
+ # A helper method that allows the current model to generate another model. This
130
+ # is useful as it allows for the current model to pass window and scene state
131
+ # to the created model.
132
+ #
133
+ # @param [String] model_name the name of the model to be created.
134
+ # @return [Metro::Model] the metro model instance
135
+ #
136
+ def create(model_name,options={})
137
+ # @TODO: this is another path that parallels the ModelFactory
138
+ model_class = Metro::Models.find(model_name)
139
+ mc = model_class.new options
140
+ mc.scene = scene
141
+ mc.window = window
142
+ mc
143
+ end
144
+
145
+ #
146
+ # By default a model has no bounds. Each subclass of model will have to
147
+ # define how their bounds are defined.
148
+ #
149
+ def bounds
150
+ Bounds.none
151
+ end
152
+
153
+ #
154
+ # Create an instance of a model.
155
+ #
156
+ # @note Overridding initialize method should be avoided, using the {#aftter_initialize)
157
+ # method or done with care to ensure that functionality is preserved.
158
+ #
159
+ def initialize(options = {})
160
+ _load(options)
161
+ after_initialize
162
+ end
163
+
164
+ #
165
+ # Loads a hash of content into the model. This process will convert the hash
166
+ # of content into setter and getter methods with appropriate ruby style names.
167
+ #
168
+ # This is used internally when the model is created for the Scene. It is loaded
169
+ # with the contents of the view.
170
+ #
171
+ def _load(options = {})
172
+ # Clean up and symbolize all the keys then merge that with the existing properties
173
+ options.keys.each do |key|
174
+ property_name = key.to_s.underscore.to_sym
175
+ if respond_to? "#{property_name}="
176
+ send("#{property_name}=",options.delete(key))
177
+ else
178
+ options[property_name] = options.delete(key)
179
+ end
180
+ end
181
+
182
+ properties.merge! options
183
+ end
184
+
185
+ #
186
+ # Generate a hash export of all the fields that were previously stored within
187
+ # the model.
188
+ #
189
+ # This is used internally within the scene to transfer the data from one model
190
+ # to another model.
191
+ #
192
+ def _save
193
+ properties
194
+ end
195
+
196
+ #
197
+ # Generate a hash representation of the model.
198
+ #
199
+ def to_hash
200
+ { name => properties.except(:name) }
201
+ end
202
+
203
+ #
204
+ # @return a common name that can be used through the system as a common identifier.
205
+ #
206
+ def self.metro_name
207
+ name.underscore
208
+ end
209
+
210
+ #
211
+ # @return an array of all ancestor models by name
212
+ #
213
+ def self.hierarchy
214
+ ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
215
+ end
216
+
217
+ #
218
+ # Captures all classes that subclass Model.
219
+ #
220
+ def self.inherited(base)
221
+ models << base.to_s
222
+ Models.add(base)
223
+ end
224
+
225
+ #
226
+ # All subclasses of Model, this should be all the defined
227
+ #
228
+ def self.models
229
+ @models ||= []
230
+ end
231
+
232
+ end
233
+ end
234
+
235
+ require_relative 'ui/ui'
236
+ require_relative 'audio/song'