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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +12 -0
- data/Guardfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +189 -0
- data/Rakefile +18 -0
- data/bin/metro +16 -0
- data/changelog.md +157 -0
- data/lib/assets/menu-movement.wav +0 -0
- data/lib/assets/menu-selection.wav +0 -0
- data/lib/assets/missing.ogg +0 -0
- data/lib/assets/missing.png +0 -0
- data/lib/assets/missing.wav +0 -0
- data/lib/assets/missing_animation.png +0 -0
- data/lib/commands/generate_game.rb +13 -0
- data/lib/commands/generate_model.rb +25 -0
- data/lib/commands/generate_scene.rb +36 -0
- data/lib/commands/generate_view.rb +21 -0
- data/lib/commands/thor.rb +83 -0
- data/lib/core_ext/class.rb +14 -0
- data/lib/core_ext/numeric.rb +59 -0
- data/lib/gosu_ext/color.rb +62 -0
- data/lib/gosu_ext/gosu_constants.rb +53 -0
- data/lib/locale/en.yml +35 -0
- data/lib/locale/locale.rb +1 -0
- data/lib/metro.rb +140 -0
- data/lib/metro/animation.rb +135 -0
- data/lib/metro/animation/after_interval_factory.rb +12 -0
- data/lib/metro/animation/animation_factory.rb +15 -0
- data/lib/metro/animation/easing/ease_in.rb +15 -0
- data/lib/metro/animation/easing/easing.rb +51 -0
- data/lib/metro/animation/easing/linear.rb +15 -0
- data/lib/metro/animation/has_animations.rb +70 -0
- data/lib/metro/animation/implicit_animation.rb +100 -0
- data/lib/metro/animation/on_update_operation.rb +96 -0
- data/lib/metro/animation/scene_animation.rb +16 -0
- data/lib/metro/asset_path.rb +97 -0
- data/lib/metro/events/control_definition.rb +11 -0
- data/lib/metro/events/controls.rb +42 -0
- data/lib/metro/events/event_data.rb +60 -0
- data/lib/metro/events/event_dictionary.rb +52 -0
- data/lib/metro/events/event_factory.rb +17 -0
- data/lib/metro/events/event_relay.rb +300 -0
- data/lib/metro/events/event_state_manager.rb +63 -0
- data/lib/metro/events/events.rb +3 -0
- data/lib/metro/events/has_events.rb +108 -0
- data/lib/metro/events/hit_list.rb +75 -0
- data/lib/metro/events/unknown_sender.rb +5 -0
- data/lib/metro/font.rb +69 -0
- data/lib/metro/game.rb +102 -0
- data/lib/metro/game/dsl.rb +68 -0
- data/lib/metro/image.rb +68 -0
- data/lib/metro/logging.rb +33 -0
- data/lib/metro/missing_scene.rb +21 -0
- data/lib/metro/models/audio/song.rb +33 -0
- data/lib/metro/models/draws.rb +86 -0
- data/lib/metro/models/key_value_coding.rb +38 -0
- data/lib/metro/models/model.rb +236 -0
- data/lib/metro/models/model_factory.rb +32 -0
- data/lib/metro/models/models.rb +62 -0
- data/lib/metro/models/properties/animation_property.rb +115 -0
- data/lib/metro/models/properties/array_property.rb +24 -0
- data/lib/metro/models/properties/boolean_property.rb +27 -0
- data/lib/metro/models/properties/color_property.rb +116 -0
- data/lib/metro/models/properties/dimensions_property.rb +84 -0
- data/lib/metro/models/properties/font_property.rb +130 -0
- data/lib/metro/models/properties/image_property.rb +96 -0
- data/lib/metro/models/properties/model_property.rb +84 -0
- data/lib/metro/models/properties/numeric_property.rb +29 -0
- data/lib/metro/models/properties/options_property/no_option.rb +29 -0
- data/lib/metro/models/properties/options_property/options.rb +94 -0
- data/lib/metro/models/properties/options_property/options_property.rb +125 -0
- data/lib/metro/models/properties/position_property.rb +90 -0
- data/lib/metro/models/properties/property.rb +221 -0
- data/lib/metro/models/properties/property_owner.rb +137 -0
- data/lib/metro/models/properties/sample_property.rb +84 -0
- data/lib/metro/models/properties/scale_property.rb +80 -0
- data/lib/metro/models/properties/song_property.rb +89 -0
- data/lib/metro/models/properties/text_property.rb +75 -0
- data/lib/metro/models/ui/animated_sprite.rb +85 -0
- data/lib/metro/models/ui/border.rb +95 -0
- data/lib/metro/models/ui/fps.rb +54 -0
- data/lib/metro/models/ui/generic.rb +66 -0
- data/lib/metro/models/ui/grid_drawer.rb +74 -0
- data/lib/metro/models/ui/image.rb +87 -0
- data/lib/metro/models/ui/label.rb +175 -0
- data/lib/metro/models/ui/menu.rb +214 -0
- data/lib/metro/models/ui/model_label.rb +65 -0
- data/lib/metro/models/ui/model_labeler.rb +79 -0
- data/lib/metro/models/ui/rectangle.rb +59 -0
- data/lib/metro/models/ui/sprite.rb +79 -0
- data/lib/metro/models/ui/tile_map.rb +162 -0
- data/lib/metro/models/ui/ui.rb +13 -0
- data/lib/metro/parameters/command_line_args_parser.rb +68 -0
- data/lib/metro/parameters/options.rb +25 -0
- data/lib/metro/parameters/parameters.rb +2 -0
- data/lib/metro/sample.rb +40 -0
- data/lib/metro/scene.rb +477 -0
- data/lib/metro/scenes.rb +154 -0
- data/lib/metro/song.rb +56 -0
- data/lib/metro/template_message.rb +60 -0
- data/lib/metro/transitions/edit_transition_scene.rb +100 -0
- data/lib/metro/transitions/fade_transition_scene.rb +66 -0
- data/lib/metro/transitions/scene_transitions.rb +44 -0
- data/lib/metro/transitions/transition_scene.rb +19 -0
- data/lib/metro/units/bounds.rb +8 -0
- data/lib/metro/units/calculation_validations.rb +74 -0
- data/lib/metro/units/dimensions.rb +60 -0
- data/lib/metro/units/point.rb +51 -0
- data/lib/metro/units/rectangle_bounds.rb +85 -0
- data/lib/metro/units/scale.rb +46 -0
- data/lib/metro/units/units.rb +6 -0
- data/lib/metro/version.rb +32 -0
- data/lib/metro/views/json_view.rb +60 -0
- data/lib/metro/views/no_view.rb +34 -0
- data/lib/metro/views/parsers.rb +42 -0
- data/lib/metro/views/scene_view.rb +107 -0
- data/lib/metro/views/view.rb +133 -0
- data/lib/metro/views/writers.rb +43 -0
- data/lib/metro/views/yaml_view.rb +94 -0
- data/lib/metro/window.rb +94 -0
- data/lib/setup_handlers/exit_if_dry_run.rb +26 -0
- data/lib/setup_handlers/game_execution.rb +65 -0
- data/lib/setup_handlers/load_game_configuration.rb +65 -0
- data/lib/setup_handlers/load_game_files.rb +101 -0
- data/lib/setup_handlers/move_to_game_directory.rb +25 -0
- data/lib/setup_handlers/reload_game_on_game_file_changes.rb +79 -0
- data/lib/templates/game/README.md.tt +52 -0
- data/lib/templates/game/assets/brand.jpg +0 -0
- data/lib/templates/game/assets/hero.png +0 -0
- data/lib/templates/game/lib/custom_easing.rb +32 -0
- data/lib/templates/game/metro.tt +63 -0
- data/lib/templates/game/models/hero.rb +62 -0
- data/lib/templates/game/scenes/brand_scene.rb +19 -0
- data/lib/templates/game/scenes/brand_to_title_scene.rb +13 -0
- data/lib/templates/game/scenes/first_scene.rb +28 -0
- data/lib/templates/game/scenes/game_scene.rb +43 -0
- data/lib/templates/game/scenes/title_scene.rb +15 -0
- data/lib/templates/game/views/brand.yaml +4 -0
- data/lib/templates/game/views/brand_to_title.yaml +8 -0
- data/lib/templates/game/views/first.yaml +26 -0
- data/lib/templates/game/views/title.yaml +11 -0
- data/lib/templates/message.erb +23 -0
- data/lib/templates/model.rb.tt +111 -0
- data/lib/templates/scene.rb.tt +140 -0
- data/lib/templates/view.yaml.tt +11 -0
- data/lib/tmxed_ext/tile_set.rb +34 -0
- data/metro.gemspec +56 -0
- data/spec/core_ext/numeric_spec.rb +78 -0
- data/spec/core_ext/string_spec.rb +33 -0
- data/spec/gosu_ext/color_spec.rb +80 -0
- data/spec/metro/events/event_state_manager_spec.rb +5 -0
- data/spec/metro/models/key_value_coding_spec.rb +61 -0
- data/spec/metro/models/properties/array_property_spec.rb +60 -0
- data/spec/metro/models/properties/color_property_spec.rb +85 -0
- data/spec/metro/models/properties/dimensions_spec.rb +29 -0
- data/spec/metro/models/properties/font_property_spec.rb +127 -0
- data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
- data/spec/metro/models/properties/options_property/no_option_spec.rb +25 -0
- data/spec/metro/models/properties/options_property/options_property_spec.rb +133 -0
- data/spec/metro/models/properties/options_property/options_spec.rb +125 -0
- data/spec/metro/models/properties/position_property_spec.rb +90 -0
- data/spec/metro/models/ui/label_spec.rb +259 -0
- data/spec/metro/parameters/command_line_args_parser_spec.rb +42 -0
- data/spec/metro/scene_spec.rb +15 -0
- data/spec/metro/scene_views/json_view_spec.rb +27 -0
- data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
- data/spec/metro/scenes_spec.rb +77 -0
- data/spec/metro/units/point_spec.rb +132 -0
- data/spec/metro/views/view_spec.rb +53 -0
- data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
- data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
- data/spec/spec_helper.rb +20 -0
- metadata +374 -0
data/lib/metro/window.rb
ADDED
@@ -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
|