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
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
|
|
3
|
+
class GenerateModel < Generator
|
|
4
|
+
|
|
5
|
+
no_tasks do
|
|
6
|
+
|
|
7
|
+
def model_filename
|
|
8
|
+
name.underscore
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def model_name
|
|
12
|
+
name.camelize
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
argument :name
|
|
18
|
+
|
|
19
|
+
def create_model_file
|
|
20
|
+
template "model.rb.tt", "models/#{model_filename}.rb"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
|
|
3
|
+
class GenerateScene < Generator
|
|
4
|
+
|
|
5
|
+
no_tasks do
|
|
6
|
+
|
|
7
|
+
def scene_filename
|
|
8
|
+
scene_name = name.gsub(/_?Scene$/i,'')
|
|
9
|
+
"#{scene_name.underscore}_scene"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def scene_class_name
|
|
13
|
+
scene_name = name.gsub(/_?Scene$/i,'')
|
|
14
|
+
"#{scene_name.camelize}Scene"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def view_filename
|
|
18
|
+
view_name = name.to_s.gsub(/_?Scene$/i,'')
|
|
19
|
+
view_name.underscore
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
argument :name
|
|
25
|
+
|
|
26
|
+
def create_scene_file
|
|
27
|
+
template "scene.rb.tt", "scenes/#{scene_filename}.rb"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def create_view_file
|
|
31
|
+
template "view.yaml.tt", "views/#{view_filename}.yaml"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
|
|
3
|
+
class GenerateView < Generator
|
|
4
|
+
|
|
5
|
+
no_tasks do
|
|
6
|
+
|
|
7
|
+
def view_filename
|
|
8
|
+
view_name = name.to_s.gsub(/_?Scene$/i,'')
|
|
9
|
+
view_name.underscore
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
argument :name
|
|
15
|
+
|
|
16
|
+
def create_view_file
|
|
17
|
+
template "view.yaml.tt", "views/#{view_filename}.yaml"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'thor/group'
|
|
3
|
+
|
|
4
|
+
module Metro
|
|
5
|
+
|
|
6
|
+
class Generator < ::Thor::Group
|
|
7
|
+
include Thor::Actions
|
|
8
|
+
|
|
9
|
+
def self.source_root
|
|
10
|
+
File.join File.dirname(__FILE__), "..", "templates"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class UnknownGenerator
|
|
15
|
+
|
|
16
|
+
def self.start(commands)
|
|
17
|
+
raise "There is no command: [ #{commands.join(', ')} ]"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Thor < Thor
|
|
24
|
+
|
|
25
|
+
no_tasks do
|
|
26
|
+
|
|
27
|
+
def banner
|
|
28
|
+
"""
|
|
29
|
+
********************************************************************************
|
|
30
|
+
______ ___ _____
|
|
31
|
+
___ |/ /_____ __ /_______________
|
|
32
|
+
__ /|_/ / _ _ \\_ __/__ ___/_ __ \\
|
|
33
|
+
_ / / / / __// /_ _ / / /_/ /
|
|
34
|
+
/_/ /_/ \\___/ \\__/ /_/ \\____/
|
|
35
|
+
|
|
36
|
+
-------------------------------------------------------------------------------"""
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def generators
|
|
40
|
+
Hash.new(UnknownGenerator).merge model: Metro::GenerateModel,
|
|
41
|
+
scene: Metro::GenerateScene,
|
|
42
|
+
view: Metro::GenerateView
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def generator(name)
|
|
46
|
+
generators[name.to_sym]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
desc "new GAMENAME",
|
|
52
|
+
"Create a new game within the directory using with the GAMENAME given."
|
|
53
|
+
def new(game_name)
|
|
54
|
+
Metro::GenerateGame.start [ game_name ]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
desc "generate TYPE NAME",
|
|
58
|
+
"Create a new type: model, view, or scene."
|
|
59
|
+
def generate(type,name)
|
|
60
|
+
gen = generator(type)
|
|
61
|
+
gen.start [ name ]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
desc "g TYPE NAME",
|
|
65
|
+
"Create a new type: model, view, or scene."
|
|
66
|
+
def g(type,name)
|
|
67
|
+
generate(type,name)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
desc "help", "This commoand"
|
|
71
|
+
def help
|
|
72
|
+
say banner
|
|
73
|
+
print_table self.class.printable_tasks, indent: 4
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
require_relative 'generate_game'
|
|
81
|
+
require_relative 'generate_model'
|
|
82
|
+
require_relative 'generate_scene'
|
|
83
|
+
require_relative 'generate_view'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
class Class
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Within Metro often times a Class or the name of the class is being used.
|
|
6
|
+
# ActiveSupport provides the constantize on Strings and Symbols but does
|
|
7
|
+
# not provide it on Class. So instead of providing redundant checks in
|
|
8
|
+
# places this monkeypatch simply makes Classes adhere to the same interface.
|
|
9
|
+
#
|
|
10
|
+
# @return [Class] itself.
|
|
11
|
+
def constantize
|
|
12
|
+
self
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class Numeric
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Set the tick interval which is used in conversion of seconds to
|
|
5
|
+
# ticks.
|
|
6
|
+
#
|
|
7
|
+
def self.tick_interval=(value)
|
|
8
|
+
@tick_interval = value.to_f
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# @return the game tick interval. By default the tick interval is 16.66666
|
|
13
|
+
#
|
|
14
|
+
def self.tick_interval
|
|
15
|
+
@tick_interval.to_f == 0 ? 16.666666 : @tick_interval.to_f
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
#
|
|
21
|
+
# Provides the suffix 'second' which will translate seconds to
|
|
22
|
+
# game ticks. This is to allow for a number of seconds to be expressed
|
|
23
|
+
# in situations where game ticks are used (e.g. animations).
|
|
24
|
+
#
|
|
25
|
+
# @example Expressing an animation that takes place over 3 seconds (~180 ticks)
|
|
26
|
+
#
|
|
27
|
+
# class ExampleScene < Metro::Scene
|
|
28
|
+
# draws :title
|
|
29
|
+
#
|
|
30
|
+
# animate :title, to: { x: 320, y: 444 }, interval: 3.seconds
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
def second
|
|
34
|
+
(self * 1000 / Numeric.tick_interval).floor
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
alias_method :seconds, :second
|
|
38
|
+
alias_method :secs, :second
|
|
39
|
+
alias_method :sec, :second
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Provides the suffix 'tick' which will simply express the number
|
|
43
|
+
# with a vanity suffix.
|
|
44
|
+
#
|
|
45
|
+
# @example Expressing an animation that takes place over 60 game ticks
|
|
46
|
+
#
|
|
47
|
+
# class ExampleScene < Metro::Scene
|
|
48
|
+
# draws :title
|
|
49
|
+
#
|
|
50
|
+
# animate :title, to: { x: 320, y: 444 }, interval: 60.ticks
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
def tick
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
alias_method :ticks, :tick
|
|
58
|
+
|
|
59
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
class Gosu::Color
|
|
2
|
+
|
|
3
|
+
alias_method :gosu_initialize, :initialize
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# Monkey-patching the initialize to allow for another Gosu::Color
|
|
7
|
+
# and Strings.
|
|
8
|
+
#
|
|
9
|
+
def initialize(*args)
|
|
10
|
+
if args.length == 1
|
|
11
|
+
value = args.first
|
|
12
|
+
if value.is_a? Gosu::Color
|
|
13
|
+
gosu_initialize value.alpha, value.red, value.green, value.blue
|
|
14
|
+
elsif value.is_a? String
|
|
15
|
+
gosu_initialize *Array(self.class.parse_string(value))
|
|
16
|
+
else
|
|
17
|
+
gosu_initialize value
|
|
18
|
+
end
|
|
19
|
+
else
|
|
20
|
+
gosu_initialize *args
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.parse_string(value)
|
|
25
|
+
parse_hex(value) || parse_rgb(value) || parse_rgba(value) || parse_gosu_color_string(value) || [ 255, 255, 255, 255 ]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.parse_rgba(rgba)
|
|
29
|
+
if rgba =~ /rgba\(([\d]{1,3}(?:\.\d*)?),([\d]{1,3}(?:\.\d*)?),([\d]{1,3}(?:\.\d*)?),(\d(?:\.\d*)?)\)/
|
|
30
|
+
[ (255 * $4.to_f).floor.to_i, $1.to_i, $2.to_i, $3.to_i ]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.parse_rgb(rgb)
|
|
35
|
+
if rgb =~ /rgb\(([\d]{1,3}),([\d]{1,3}),([\d]{1,3})\)/
|
|
36
|
+
[ 255, $1.to_i, $2.to_i, $3.to_i ]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.parse_hex(hex)
|
|
41
|
+
if hex =~ /0x([A-Fa-f0-9]{8})/
|
|
42
|
+
hex.to_i(16)
|
|
43
|
+
elsif hex =~ /#([A-Fa-f0-9]{6})/
|
|
44
|
+
"0xFF#{$1}".to_i(16)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.parse_gosu_color_string(string)
|
|
49
|
+
if string =~ /\(ARGB: ([\d]{1,3})\/([\d]{1,3})\/([\d]{1,3})\/([\d]{1,3})\)/
|
|
50
|
+
[ $1.to_i, $2.to_i, $3.to_i, $4.to_i ]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def to_s
|
|
55
|
+
"rgba(#{red},#{green},#{blue},#{alpha / 255.to_f})"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def to_json(*params)
|
|
59
|
+
to_s.to_json
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# The GosuEvents module creates aliases for the Keyboard and the Gamepad events
|
|
5
|
+
# within the Gosu Namespace. This is so Metro can use the events without requiring
|
|
6
|
+
# the namespace.
|
|
7
|
+
#
|
|
8
|
+
# This makes the interface of these events more portable.
|
|
9
|
+
#
|
|
10
|
+
module GosuConstants
|
|
11
|
+
|
|
12
|
+
def self.extended(base)
|
|
13
|
+
add constants: keyboard_events, to: base
|
|
14
|
+
add constants: gamepad_events, to: base
|
|
15
|
+
add constants: mouse_events, to: base
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#
|
|
19
|
+
# @return the constant from which to search for all the other constants.
|
|
20
|
+
# This helper method is to to save sprinkling the constant value
|
|
21
|
+
# throughout the rest of the module.
|
|
22
|
+
def self.gosu
|
|
23
|
+
Gosu
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.keyboard_events
|
|
27
|
+
find_all_constants_with_prefix "Kb"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.gamepad_events
|
|
31
|
+
find_all_constants_with_prefix "Gp"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.mouse_events
|
|
35
|
+
find_all_constants_with_prefix "Ms"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.find_all_constants_with_prefix(prefix)
|
|
39
|
+
gosu.constants.find_all { |c| c.to_s.start_with? prefix }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# Alias the list of given constants within the given class.
|
|
44
|
+
#
|
|
45
|
+
def self.add(options={})
|
|
46
|
+
events = options[:constants]
|
|
47
|
+
target = options[:to]
|
|
48
|
+
|
|
49
|
+
events.each {|event| target.const_set event, gosu.const_get(event) }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/locale/en.yml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
en:
|
|
3
|
+
website: "%{website}"
|
|
4
|
+
error:
|
|
5
|
+
unloadable_source:
|
|
6
|
+
title: "Metro CANNOT load your game code!"
|
|
7
|
+
message: "There is an error within your game code that needs to be fixed before Metro\nis able to replace the current running game code:\n\n%{output}"
|
|
8
|
+
actions: []
|
|
9
|
+
missing_metro_file:
|
|
10
|
+
title: "Unable to find Metro game file"
|
|
11
|
+
message: "The specified file `%{file}` which is required to run the game could not be found."
|
|
12
|
+
actions:
|
|
13
|
+
- "Ensure you have specified the correct file"
|
|
14
|
+
- "Ensure that the file exists at that location"
|
|
15
|
+
- "Did you mean to generate a new game, scene, or model? Try: `metro help`"
|
|
16
|
+
specified_directory:
|
|
17
|
+
title: "Path specified is a directory"
|
|
18
|
+
message: "The specified path is a `%{directory}` and not a valid Metro game file."
|
|
19
|
+
actions:
|
|
20
|
+
- "Ensure you have specified the correct file"
|
|
21
|
+
- "Specify the path to the metro game file with the directory included."
|
|
22
|
+
- "Did you mean to generate a new game, scene, or model? Try: `metro help`"
|
|
23
|
+
reserved_control_name:
|
|
24
|
+
title: "Unable to define control: %{name}"
|
|
25
|
+
message: "The specified control name `%{name}` is RESERVED or ALREADY DEFINED."
|
|
26
|
+
actions:
|
|
27
|
+
- "Ensure that the control name is not already defined."
|
|
28
|
+
- "Replace the use of this control name with name"
|
|
29
|
+
dry_run:
|
|
30
|
+
success:
|
|
31
|
+
title: "Metro Game Dependencies Have Been Met!"
|
|
32
|
+
message: "Your game should be able to be run."
|
|
33
|
+
actions:
|
|
34
|
+
- "Metro dependencies have successfully been loaded"
|
|
35
|
+
- "Game dependencies have successfully been loaded"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
I18n.load_path.push "#{File.dirname(__FILE__)}/en.yml"
|
data/lib/metro.rb
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
require 'delegate'
|
|
2
|
+
require 'logger'
|
|
3
|
+
require 'erb'
|
|
4
|
+
require 'open3'
|
|
5
|
+
|
|
6
|
+
require 'gosu'
|
|
7
|
+
require 'i18n'
|
|
8
|
+
require 'listen'
|
|
9
|
+
require 'tmxed'
|
|
10
|
+
require 'active_support'
|
|
11
|
+
require 'active_support/dependencies'
|
|
12
|
+
require 'active_support/inflector'
|
|
13
|
+
require 'active_support/core_ext/hash'
|
|
14
|
+
require 'active_support/hash_with_indifferent_access'
|
|
15
|
+
|
|
16
|
+
require 'gosu_ext/color'
|
|
17
|
+
require 'gosu_ext/gosu_constants'
|
|
18
|
+
require 'core_ext/numeric'
|
|
19
|
+
require 'core_ext/class'
|
|
20
|
+
require 'tmxed_ext/tile_set'
|
|
21
|
+
|
|
22
|
+
require 'locale/locale'
|
|
23
|
+
|
|
24
|
+
require 'metro/parameters/parameters'
|
|
25
|
+
require 'metro/asset_path'
|
|
26
|
+
require 'metro/units/units'
|
|
27
|
+
require 'metro/logging'
|
|
28
|
+
require 'metro/version'
|
|
29
|
+
require 'metro/animation'
|
|
30
|
+
require 'metro/font'
|
|
31
|
+
require 'metro/image'
|
|
32
|
+
require 'metro/sample'
|
|
33
|
+
require 'metro/song'
|
|
34
|
+
require 'metro/template_message'
|
|
35
|
+
require 'metro/window'
|
|
36
|
+
require 'metro/game'
|
|
37
|
+
require 'metro/scene'
|
|
38
|
+
require 'metro/scenes'
|
|
39
|
+
require 'metro/models/model'
|
|
40
|
+
require 'metro/missing_scene'
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# To allow an author an easier time accessing the Game object from within their game.
|
|
44
|
+
# They do not have to use the `Metro::Game` an instead use the `Game` constant.
|
|
45
|
+
#
|
|
46
|
+
Game = Metro::Game
|
|
47
|
+
|
|
48
|
+
module Metro
|
|
49
|
+
extend self
|
|
50
|
+
extend GosuConstants
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# @return [String] the filepath to the Metro executable
|
|
54
|
+
#
|
|
55
|
+
def executable_path
|
|
56
|
+
File.absolute_path File.join(File.dirname(__FILE__), "..", "bin", "metro")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# @return [String] the filepath to the Metro assets
|
|
61
|
+
#
|
|
62
|
+
def asset_dir
|
|
63
|
+
File.join File.dirname(__FILE__), "assets"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
# @return [Array] an array of all the handlers that will be executed prior
|
|
68
|
+
# to the game being launched.
|
|
69
|
+
#
|
|
70
|
+
def setup_handlers
|
|
71
|
+
@setup_handlers ||= []
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
#
|
|
75
|
+
# Register a setup handler. While this method is present, it is far
|
|
76
|
+
# too late for game code to be executed as these pregame handlers will already
|
|
77
|
+
# have started executing. This allows for modularity within the Metro library
|
|
78
|
+
# with the possibility that this functionality could become available to
|
|
79
|
+
# individual games if the load process were to be updated.
|
|
80
|
+
#
|
|
81
|
+
def register_setup_handler(handler)
|
|
82
|
+
setup_handlers.push handler
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# Run will load the contents of the game contents and game files
|
|
87
|
+
# within the current working directory and start the game.
|
|
88
|
+
#
|
|
89
|
+
# @param [Array<String>] parameters an array of parameters that contains
|
|
90
|
+
# the commands in the format that would normally be parsed into the
|
|
91
|
+
# ARGV array.
|
|
92
|
+
#
|
|
93
|
+
def run(*parameters)
|
|
94
|
+
options = Parameters::CommandLineArgsParser.parse(parameters)
|
|
95
|
+
setup_handlers.each { |handler| handler.setup(options) }
|
|
96
|
+
start_game
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#
|
|
100
|
+
# Start the game by lanunching a window with the game configuration and data
|
|
101
|
+
# that has been loaded.
|
|
102
|
+
#
|
|
103
|
+
def start_game
|
|
104
|
+
Game.start!
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
#
|
|
108
|
+
# When called all the game-related code will be unloaded and reloaded.
|
|
109
|
+
# Providding an opportunity for a game author to tweak the code without having
|
|
110
|
+
# to restart the game.
|
|
111
|
+
#
|
|
112
|
+
def reload!
|
|
113
|
+
SetupHandlers::LoadGameFiles.new.load_game_files!
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
#
|
|
117
|
+
# When called the game-related code will be loaded in a sub-process to see
|
|
118
|
+
# if the code is valid. This is used in tandem with {#reload} and should be
|
|
119
|
+
# called prior to ensure that the code that is replacing the current code
|
|
120
|
+
# is valid.
|
|
121
|
+
#
|
|
122
|
+
# @return [TrueClass,FalseClass] true if the game code that was loaded was
|
|
123
|
+
# loaded successfully. false if the game code was not able to be loaded.
|
|
124
|
+
#
|
|
125
|
+
def game_has_valid_code?
|
|
126
|
+
execution = SetupHandlers::LoadGameFiles.new.launch_game_in_dry_run_mode
|
|
127
|
+
|
|
128
|
+
if execution.invalid?
|
|
129
|
+
error! 'error.unloadable_source', output: execution.output, exit: false
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
execution.valid?
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
require 'setup_handlers/move_to_game_directory'
|
|
137
|
+
require 'setup_handlers/load_game_files'
|
|
138
|
+
require 'setup_handlers/load_game_configuration'
|
|
139
|
+
require 'setup_handlers/exit_if_dry_run'
|
|
140
|
+
require 'setup_handlers/reload_game_on_game_file_changes'
|