metro-ld26 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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'