metro-ld25 0.3.3

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 (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,94 @@
1
+ module Metro
2
+
3
+ #
4
+ # A subclass of the Gosu::Window which simply acts as system
5
+ # to shuffle in and out scenes and relay event information.
6
+ #
7
+ class Window < Gosu::Window
8
+
9
+ #
10
+ # The scene of the window.
11
+ #
12
+ # @see Scene
13
+ #
14
+ attr_accessor :scene
15
+
16
+ def state
17
+ scene.state
18
+ end
19
+
20
+ #
21
+ # @param [Fixnum] width the width of the game window
22
+ # @param [Fixnum] height the height of the game window
23
+ # @param [TrueClass,FalseClass] fullscreen the boolean flag to enable or
24
+ # disable fullscreen
25
+ #
26
+ def initialize(width,height,fullscreen)
27
+ super width, height, fullscreen
28
+ end
29
+
30
+ def scene=(scene)
31
+ scene.window = self
32
+ @scene = scene
33
+ end
34
+
35
+ #
36
+ # This is called every update interval while the window is being shown.
37
+ #
38
+ def update
39
+ state.fire_events_for_held_buttons
40
+ scene.base_update
41
+ end
42
+
43
+ #
44
+ # This is called after every {#update} and when the OS wants the window to
45
+ # repaint itself.
46
+ #
47
+ def draw
48
+ scene.base_draw
49
+ end
50
+
51
+ #
52
+ # Called before {#update} when the user releases a button while the window
53
+ # has focus.
54
+ #
55
+ def button_up(id)
56
+ state.fire_button_up(id)
57
+ end
58
+
59
+ #
60
+ # Called before {#update} when the user presses a button while the window
61
+ # has focus.
62
+ #
63
+ def button_down(id)
64
+ state.fire_button_down(id)
65
+ end
66
+
67
+ #
68
+ # @return the dimensions of the current window.
69
+ #
70
+ def dimensions
71
+ Metro::Units::Dimensions.of width, height
72
+ end
73
+
74
+ #
75
+ # Define an acessor that enables/disables the use of a cursor
76
+ # within the window. The value should be truthy/falsy.
77
+ #
78
+ attr_accessor :cursor
79
+
80
+ #
81
+ # Gosu uses this method to determine if the cursor should be shown.
82
+ #
83
+ alias_method :needs_cursor?, :cursor
84
+
85
+ def show_cursor
86
+ self.cursor = true
87
+ end
88
+
89
+ def hide_cursor
90
+ self.cursor = false
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,26 @@
1
+ module Metro
2
+ module SetupHandlers
3
+
4
+ #
5
+ # If the user has enabled the dry-run flag, this is the point at which the
6
+ # game will exit.
7
+ #
8
+ # Dry run mode is useful for determine if all dependencies have successfully
9
+ # been met and the source code will load successfully.
10
+ #
11
+ class ExitIfDryRun
12
+ #
13
+ # @param [Metro::Parameters::Options] options the options that the game
14
+ # was provided when it was launched.
15
+ #
16
+ def setup(options)
17
+ return unless options.dry_run?
18
+ puts TemplateMessage.new message: 'dry_run.success'
19
+ exit
20
+ end
21
+ end
22
+ end
23
+
24
+ register_setup_handler SetupHandlers::ExitIfDryRun.new
25
+
26
+ end
@@ -0,0 +1,65 @@
1
+ module Metro
2
+ module SetupHandlers
3
+
4
+ #
5
+ # The GameExecution allows for a game to be executed. This is used by Metro
6
+ # to validate that the code can be loaded and run before actually running
7
+ # it (specifically when reloading live running code)
8
+ #
9
+ class GameExecution
10
+
11
+ #
12
+ # Perform a game execution with the specified parameters and return the
13
+ # result of that game execution.
14
+ #
15
+ def self.execute(parameters)
16
+ execution = new(parameters)
17
+ execution.execute!
18
+ execution
19
+ end
20
+
21
+ # @return the output generated from the execution of code.
22
+ attr_reader :output
23
+
24
+ # @return an array of parameters that will be provided to the execution
25
+ # of the game.
26
+ attr_reader :parameters
27
+
28
+ #
29
+ # @param [Array] parameters an array of the game parameters that are
30
+ # to be provided to this execution of the game.
31
+ #
32
+ def initialize(parameters)
33
+ @parameters = parameters
34
+ end
35
+
36
+ # @return the status code that was returned when the game execution
37
+ # has completed.
38
+ def status
39
+ @status ||= 0
40
+ end
41
+
42
+ # Perform the game execution.
43
+ def execute!
44
+ @output, @status = Open3.capture2e(game_execution_string)
45
+ end
46
+
47
+ # @return [TrueClass,FalseClass] true if the execution was successful.
48
+ def valid?
49
+ status == 0
50
+ end
51
+
52
+ # @return [TrueClass,FalseClass] true if the execution was a failure.
53
+ def invalid?
54
+ status != 0
55
+ end
56
+
57
+ private
58
+
59
+ def game_execution_string
60
+ "#{Metro.executable_path} #{parameters.join(" ")}"
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,65 @@
1
+ module Metro
2
+ module SetupHandlers
3
+
4
+ #
5
+ # LoadGameConfiguration is a meta pregame setup handler as it defines multiple
6
+ # setup handlers to be executed related to game configuration.
7
+ #
8
+ class GameConfiguration
9
+ #
10
+ # @param [Metro::Parameters::Options] options the options that the game
11
+ # was provided when it was launched.
12
+ #
13
+ def setup(options)
14
+ ParseAndLoadGameConfiguration.new.setup(options)
15
+ ConfigureControls.new.setup(options)
16
+ end
17
+ end
18
+
19
+ #
20
+ # Loads the game configuration information and sets up a Game object with the
21
+ # content loaded from the game configuration.
22
+ #
23
+ class ParseAndLoadGameConfiguration
24
+
25
+ #
26
+ # @param [Metro::Parameters::Options] options the options that the game
27
+ # was provided when it was launched.
28
+ #
29
+ def setup(options)
30
+ filename = options.filename
31
+
32
+ Game.execution_parameters = options.execution_parameters
33
+
34
+ gamefile = File.basename(filename)
35
+ game_files_exist!(gamefile)
36
+ game_contents = File.read(gamefile)
37
+ game_block = lambda {|instance| eval(game_contents) }
38
+ game = Game::DSL.parse(&game_block)
39
+ Game.setup game
40
+ end
41
+
42
+ def game_files_exist!(*files)
43
+ files.compact.flatten.each { |file| game_file_exists?(file) }
44
+ end
45
+
46
+ def game_file_exists?(file)
47
+ error!("error.missing_metro_file",file: file) unless File.exists?(file)
48
+ error!("error.specified_directory",directory: file) if File.directory?(file)
49
+ end
50
+ end
51
+
52
+ #
53
+ # After the game has been configured it is time to configure the controls for
54
+ # the game.
55
+ #
56
+ class ConfigureControls
57
+ def setup(options)
58
+ EventRelay.define_controls Game.controls
59
+ end
60
+ end
61
+ end
62
+
63
+ register_setup_handler SetupHandlers::GameConfiguration.new
64
+
65
+ end
@@ -0,0 +1,101 @@
1
+ require_relative 'game_execution'
2
+
3
+ module Metro
4
+ module SetupHandlers
5
+
6
+ #
7
+ # LoadGameFiles will load all the game files within the current working
8
+ # directory that are in the pre-defined Metro game folders.
9
+ #
10
+ # LoadGameFiles uses ActiveSupport::Dependencies::WatchStack to spy on all
11
+ # the constants that are added when the game runs. This grants the class
12
+ # the ability to provide dynamic reloading of the classes as they change.
13
+ #
14
+ class LoadGameFiles
15
+
16
+ #
17
+ # @param [Metro::Parameters::Options] options the options that the game
18
+ # was provided when it was launched.
19
+ #
20
+ def setup(options)
21
+ load_game_files!
22
+ end
23
+
24
+ #
25
+ # Drop any already defined events. Drop all the existing classes, reload
26
+ # the game files, and prepare the new game files for unloading the next
27
+ # time around that reload has been called.
28
+ #
29
+ def load_game_files!
30
+ EventDictionary.reset!
31
+ Image.images.clear
32
+ Animation.images.clear
33
+ Song.songs.clear
34
+ Font.fonts.clear
35
+
36
+ prepare_watcher!
37
+ load_game_files
38
+ execute_watcher!
39
+ end
40
+
41
+ #
42
+ # Launch the game in a sub-process in dry-run mode. Starting the
43
+ # game in dry-run mode here makes it so it will not launch a window
44
+ # and simply check to see if the code is valid and working correctly.
45
+ #
46
+ def launch_game_in_dry_run_mode
47
+ GameExecution.execute Game.execution_parameters + [ "--dry-run" ]
48
+ end
49
+
50
+ #
51
+ # The watcher should watch the Object Namespace for any changes. Any constants
52
+ # that are added will be tracked from this point forward.
53
+ #
54
+ def prepare_watcher!
55
+ ActiveSupport::Dependencies.clear
56
+ watcher.watch_namespaces([ Object ])
57
+ end
58
+
59
+ #
60
+ # The watcher will keep track of all the constants that were added to the Object
61
+ # Namespace after the start of the execution of the game. This will allow for only
62
+ # those objects to be reloaded.
63
+ #
64
+ def watcher
65
+ @watcher ||= ActiveSupport::Dependencies::WatchStack.new
66
+ end
67
+
68
+ def load_game_files
69
+ $LOAD_PATH.unshift(Dir.pwd) unless $LOAD_PATH.include?(Dir.pwd)
70
+ load_paths 'lib'
71
+ load_path 'scenes', prioritize: 'game_scene.rb'
72
+ load_path 'models', prioritize: 'game_model.rb'
73
+ end
74
+
75
+ def load_paths(*paths)
76
+ paths.flatten.compact.each {|path| load_path path }
77
+ end
78
+
79
+ def load_path(path,options = {})
80
+ files = Dir["#{path}/**/*.rb"]
81
+ files.sort! {|file| File.basename(file) == options[:prioritize] ? -1 : 1 }
82
+ files.each {|file| require_or_load file }
83
+ end
84
+
85
+ #
86
+ # The watcher will now mark all the constants that it has watched being loaded
87
+ # as unloadable. Doing so exhausts the list of constants found so the watcher
88
+ # will be empty.
89
+ #
90
+ # @note an exception is raised if the watcher is not prepared every time this
91
+ # is called.
92
+ #
93
+ def execute_watcher!
94
+ watcher.new_constants.each { |constant| unloadable constant }
95
+ end
96
+ end
97
+ end
98
+
99
+ register_setup_handler SetupHandlers::LoadGameFiles.new
100
+
101
+ end
@@ -0,0 +1,25 @@
1
+ module Metro
2
+ module SetupHandlers
3
+
4
+ #
5
+ # If the filename provide contains path information, then we need to move the
6
+ # current working directory into the root of the game directory. This is
7
+ # important because assets and other various paths are dependent on that
8
+ # being the location during execution.
9
+ #
10
+ class MoveToGameDirectory
11
+ #
12
+ # @param [Metro::Parameters::Options] options the options that the game
13
+ # was provided when it was launched.
14
+ #
15
+ def setup(options)
16
+ filename = options.filename
17
+ game_directory = File.dirname(filename)
18
+ Dir.chdir game_directory
19
+ end
20
+ end
21
+ end
22
+
23
+ register_setup_handler SetupHandlers::MoveToGameDirectory.new
24
+
25
+ end
@@ -0,0 +1,79 @@
1
+ module Metro
2
+ module SetupHandlers
3
+
4
+ #
5
+ # When the game is launched in **debug** mode the game directories will be
6
+ # monitored for changes. When a change occurs within one of the game source
7
+ # files the game and scene will be reloaded.
8
+ #
9
+ class ReloadGameOnGameFileChanges
10
+
11
+ def watched_filepaths
12
+ source_filepaths + view_filepaths + asset_filepaths
13
+ end
14
+
15
+ #
16
+ # @NOTE this is duplication of the paths is also defined in LoadGameFiles.
17
+ # @see Metro::SetupHandlers::LoadGameFiles
18
+ #
19
+ def source_filepaths
20
+ [ 'lib', 'scenes', 'models' ]
21
+ end
22
+
23
+ def view_filepaths
24
+ [ 'views' ]
25
+ end
26
+
27
+ def asset_filepaths
28
+ [ 'assets' ]
29
+ end
30
+
31
+ #
32
+ # @param [Metro::Parameters::Options] options the options that the game
33
+ # was provided when it was launched.
34
+ #
35
+ def setup(options)
36
+ start_watcher if Game.debug? and not options.packaged?
37
+ end
38
+
39
+ def start_watcher
40
+ Thread.abort_on_exception = true
41
+ Thread.new { watch_filepaths(watched_filepaths) }
42
+ end
43
+
44
+ #
45
+ # Defines the listener that will watch the filepaths
46
+ #
47
+ def watch_filepaths(filepaths)
48
+ listener = Listen.to(*filepaths)
49
+ listener.change(&on_change)
50
+ listener.start
51
+ end
52
+
53
+ #
54
+ # @return [Proc] the body of code to execute when a file change event has
55
+ # been received.
56
+ #
57
+ def on_change
58
+ Proc.new { |modified,added,removed| reload_game_because_files_changed(modified + added + removed) }
59
+ end
60
+
61
+ #
62
+ # Perform a game reload if the game source is valid.
63
+ #
64
+ def reload_game_because_files_changed(changed)
65
+ log.debug "Metro has detected #{changed.count} game source #{changed.count != 1 ? 'files have' : 'file has'} changed. RELOADING GAME CODE!"
66
+ if Metro.game_has_valid_code?
67
+ Game.current_scene.after(1.tick) do
68
+ Metro.reload!
69
+ scene_is_being_edited = scene_name == "metro/edit_transition"
70
+ transition_to(scene_name) unless scene_is_being_edited
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+
78
+ register_setup_handler SetupHandlers::ReloadGameOnGameFileChanges.new
79
+ end