metro-ld25 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|