metro-ld26 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +14 -0
  6. data/Guardfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +177 -0
  9. data/Rakefile +18 -0
  10. data/bin/metro +16 -0
  11. data/changelog.md +153 -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 +144 -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 +342 -0
  47. data/lib/metro/events/event_state_manager.rb +70 -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 +75 -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 +246 -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 +98 -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 +132 -0
  96. data/lib/metro/models/ui/tmx/isometric_position.rb +43 -0
  97. data/lib/metro/models/ui/tmx/orthogonal_position.rb +15 -0
  98. data/lib/metro/models/ui/tmx/tile_layer.rb +78 -0
  99. data/lib/metro/models/ui/ui.rb +13 -0
  100. data/lib/metro/parameters/command_line_args_parser.rb +68 -0
  101. data/lib/metro/parameters/options.rb +25 -0
  102. data/lib/metro/parameters/parameters.rb +2 -0
  103. data/lib/metro/sample.rb +40 -0
  104. data/lib/metro/scene.rb +478 -0
  105. data/lib/metro/scenes.rb +154 -0
  106. data/lib/metro/song.rb +56 -0
  107. data/lib/metro/template_message.rb +60 -0
  108. data/lib/metro/transitions/edit_transition_scene.rb +100 -0
  109. data/lib/metro/transitions/fade_transition_scene.rb +66 -0
  110. data/lib/metro/transitions/scene_transitions.rb +44 -0
  111. data/lib/metro/transitions/transition_scene.rb +19 -0
  112. data/lib/metro/units/bounds.rb +8 -0
  113. data/lib/metro/units/calculation_validations.rb +74 -0
  114. data/lib/metro/units/dimensions.rb +60 -0
  115. data/lib/metro/units/point.rb +51 -0
  116. data/lib/metro/units/rectangle_bounds.rb +148 -0
  117. data/lib/metro/units/scale.rb +46 -0
  118. data/lib/metro/units/units.rb +6 -0
  119. data/lib/metro/version.rb +32 -0
  120. data/lib/metro/views/json_view.rb +60 -0
  121. data/lib/metro/views/no_view.rb +34 -0
  122. data/lib/metro/views/parsers.rb +42 -0
  123. data/lib/metro/views/scene_view.rb +107 -0
  124. data/lib/metro/views/view.rb +133 -0
  125. data/lib/metro/views/writers.rb +43 -0
  126. data/lib/metro/views/yaml_view.rb +94 -0
  127. data/lib/metro/window.rb +95 -0
  128. data/lib/setup_handlers/exit_if_dry_run.rb +26 -0
  129. data/lib/setup_handlers/game_execution.rb +65 -0
  130. data/lib/setup_handlers/load_game_configuration.rb +65 -0
  131. data/lib/setup_handlers/load_game_files.rb +101 -0
  132. data/lib/setup_handlers/move_to_game_directory.rb +25 -0
  133. data/lib/setup_handlers/reload_game_on_game_file_changes.rb +79 -0
  134. data/lib/templates/game/README.md.tt +43 -0
  135. data/lib/templates/game/assets/brand.jpg +0 -0
  136. data/lib/templates/game/assets/hero.png +0 -0
  137. data/lib/templates/game/lib/custom_easing.rb +32 -0
  138. data/lib/templates/game/metro.tt +63 -0
  139. data/lib/templates/game/models/hero.rb +62 -0
  140. data/lib/templates/game/scenes/brand_scene.rb +19 -0
  141. data/lib/templates/game/scenes/brand_to_title_scene.rb +13 -0
  142. data/lib/templates/game/scenes/first_scene.rb +28 -0
  143. data/lib/templates/game/scenes/game_scene.rb +43 -0
  144. data/lib/templates/game/scenes/title_scene.rb +15 -0
  145. data/lib/templates/game/views/brand.yaml +4 -0
  146. data/lib/templates/game/views/brand_to_title.yaml +8 -0
  147. data/lib/templates/game/views/first.yaml +26 -0
  148. data/lib/templates/game/views/title.yaml +11 -0
  149. data/lib/templates/message.erb +23 -0
  150. data/lib/templates/model.rb.tt +111 -0
  151. data/lib/templates/scene.rb.tt +140 -0
  152. data/lib/templates/view.yaml.tt +11 -0
  153. data/lib/tmx_ext/object.rb +26 -0
  154. data/lib/tmx_ext/tile_set.rb +41 -0
  155. data/metro.gemspec +57 -0
  156. data/metro.png +0 -0
  157. data/spec/core_ext/numeric_spec.rb +78 -0
  158. data/spec/core_ext/string_spec.rb +33 -0
  159. data/spec/gosu_ext/color_spec.rb +80 -0
  160. data/spec/metro/image_spec.rb +33 -0
  161. data/spec/metro/models/key_value_coding_spec.rb +61 -0
  162. data/spec/metro/models/properties/array_property_spec.rb +60 -0
  163. data/spec/metro/models/properties/color_property_spec.rb +85 -0
  164. data/spec/metro/models/properties/dimensions_spec.rb +29 -0
  165. data/spec/metro/models/properties/font_property_spec.rb +127 -0
  166. data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
  167. data/spec/metro/models/properties/options_property/no_option_spec.rb +25 -0
  168. data/spec/metro/models/properties/options_property/options_property_spec.rb +133 -0
  169. data/spec/metro/models/properties/options_property/options_spec.rb +125 -0
  170. data/spec/metro/models/properties/position_property_spec.rb +90 -0
  171. data/spec/metro/models/ui/label_spec.rb +259 -0
  172. data/spec/metro/parameters/command_line_args_parser_spec.rb +42 -0
  173. data/spec/metro/scene_spec.rb +15 -0
  174. data/spec/metro/scene_views/json_view_spec.rb +27 -0
  175. data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
  176. data/spec/metro/scenes_spec.rb +77 -0
  177. data/spec/metro/units/point_spec.rb +132 -0
  178. data/spec/metro/units/rectangle_bounds_spec.rb +56 -0
  179. data/spec/metro/views/view_spec.rb +53 -0
  180. data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
  181. data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
  182. data/spec/spec_helper.rb +20 -0
  183. data/spec/tmx_ext/object_spec.rb +96 -0
  184. data/spec/tmx_ext/tile_set_spec.rb +24 -0
  185. metadata +379 -0
@@ -0,0 +1,75 @@
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
+ def self.crop(window,image,bounds)
54
+ cropped_image = TexPlay.create_image(window,bounds.width,bounds.height)
55
+ cropped_image.refresh_cache
56
+ cropped_image.splice image, 0, 0, crop: [ bounds.left, bounds.top, bounds.right, bounds.bottom ]
57
+ cropped_image
58
+ end
59
+
60
+ private
61
+
62
+ def self.create_params(options)
63
+ options.symbolize_keys!
64
+ asset_path = AssetPath.with(options[:path])
65
+ window = options[:window]
66
+ tileable = !!options[:tileable]
67
+ [ window, asset_path, tileable ]
68
+ end
69
+
70
+ def self.images
71
+ @images ||= {}
72
+ end
73
+
74
+ end
75
+ 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,246 @@
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 #update_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 update_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
+ #
69
+ # This is called after a draw. A model normally is not removed after
70
+ # a draw, however if the model responds true to #draw_completed? then it
71
+ # will be removed.
72
+ #
73
+ # @note This method should be implemented in the Model sublclass if you
74
+ # are interested in having the model be removed from the scene.
75
+ #
76
+ def draw_completed? ; false ; end
77
+
78
+ def self.model_name(model_name=nil)
79
+ @model_name ||= to_s.underscore
80
+ model_name ? @model_name = model_name.to_s : @model_name
81
+ end
82
+
83
+ #
84
+ # @return [String] the name of the model class.
85
+ #
86
+ property :model, type: :text
87
+
88
+ #
89
+ # @return [String] the name of model as it is used within the view or the scene.
90
+ # This is the common name, the key within the view file, or the name symbol
91
+ # name specified in the scene.
92
+ #
93
+ property :name, type: :text
94
+
95
+ #
96
+ # @return [TrueClass,FalseClass] true if the model should be saved to the
97
+ # view file, false when the model should not be savedable to the view file.
98
+ #
99
+ property :saveable_to_view, type: :boolean, default: true
100
+
101
+ #
102
+ # The window that this model that this window is currently being
103
+ # displayed.
104
+ #
105
+ # The current value of window is managed by the scene
106
+ # as this is set when the Scene is added to the window. All the
107
+ # models gain access to the window.
108
+ #
109
+ # @see Window
110
+ #
111
+ attr_accessor :window
112
+
113
+ #
114
+ # The scene that this model is currently being displayed.
115
+ #
116
+ # The current value of scene is managed by the scene as this
117
+ # is set when the scene is created.
118
+ #
119
+ # @see Scene
120
+ attr_accessor :scene
121
+
122
+ include KeyValueCoding
123
+
124
+ #
125
+ # Generate a custom notification event with the given name.
126
+ #
127
+ # @param [Symbol] event the name of the notification to generate.
128
+ #
129
+ def notification(event)
130
+ scene.notification(event.to_sym,self)
131
+ end
132
+
133
+ #
134
+ # Allows for the definition of events within the scene.
135
+ #
136
+ include HasEvents
137
+
138
+ #
139
+ # A helper method that allows the current model to generate another model. This
140
+ # is useful as it allows for the current model to pass window and scene state
141
+ # to the created model.
142
+ #
143
+ # @param [String] model_name the name of the model to be created.
144
+ # @return [Metro::Model] the metro model instance
145
+ #
146
+ def create(model_name,options={})
147
+ # @TODO: this is another path that parallels the ModelFactory
148
+ model_class = Metro::Models.find(model_name)
149
+ mc = model_class.new options
150
+ mc.scene = scene
151
+ mc.window = window
152
+ mc
153
+ end
154
+
155
+ #
156
+ # By default a model has no bounds. Each subclass of model will have to
157
+ # define how their bounds are defined.
158
+ #
159
+ def bounds
160
+ Bounds.none
161
+ end
162
+
163
+ #
164
+ # Create an instance of a model.
165
+ #
166
+ # @note Overridding initialize method should be avoided, using the {#aftter_initialize)
167
+ # method or done with care to ensure that functionality is preserved.
168
+ #
169
+ def initialize(options = {})
170
+ _load(options)
171
+ after_initialize
172
+ end
173
+
174
+ #
175
+ # Loads a hash of content into the model. This process will convert the hash
176
+ # of content into setter and getter methods with appropriate ruby style names.
177
+ #
178
+ # This is used internally when the model is created for the Scene. It is loaded
179
+ # with the contents of the view.
180
+ #
181
+ def _load(options = {})
182
+ # Clean up and symbolize all the keys then merge that with the existing properties
183
+ options.keys.each do |key|
184
+ property_name = key.to_s.underscore.to_sym
185
+ if respond_to? "#{property_name}="
186
+ send("#{property_name}=",options.delete(key))
187
+ else
188
+ options[property_name] = options.delete(key)
189
+ end
190
+ end
191
+
192
+ properties.merge! options
193
+ end
194
+
195
+ #
196
+ # Generate a hash export of all the fields that were previously stored within
197
+ # the model.
198
+ #
199
+ # This is used internally within the scene to transfer the data from one model
200
+ # to another model.
201
+ #
202
+ def _save
203
+ properties
204
+ end
205
+
206
+ #
207
+ # Generate a hash representation of the model.
208
+ #
209
+ def to_hash
210
+ { name => properties.except(:name) }
211
+ end
212
+
213
+ #
214
+ # @return a common name that can be used through the system as a common identifier.
215
+ #
216
+ def self.metro_name
217
+ name.underscore
218
+ end
219
+
220
+ #
221
+ # @return an array of all ancestor models by name
222
+ #
223
+ def self.hierarchy
224
+ ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
225
+ end
226
+
227
+ #
228
+ # Captures all classes that subclass Model.
229
+ #
230
+ def self.inherited(base)
231
+ models << base.to_s
232
+ Models.add(base)
233
+ end
234
+
235
+ #
236
+ # All subclasses of Model, this should be all the defined
237
+ #
238
+ def self.models
239
+ @models ||= []
240
+ end
241
+
242
+ end
243
+ end
244
+
245
+ require_relative 'ui/ui'
246
+ require_relative 'audio/song'