metro-ld26 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +14 -0
- data/Guardfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +177 -0
- data/Rakefile +18 -0
- data/bin/metro +16 -0
- data/changelog.md +153 -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 +144 -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 +342 -0
- data/lib/metro/events/event_state_manager.rb +70 -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 +75 -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 +246 -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 +98 -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 +132 -0
- data/lib/metro/models/ui/tmx/isometric_position.rb +43 -0
- data/lib/metro/models/ui/tmx/orthogonal_position.rb +15 -0
- data/lib/metro/models/ui/tmx/tile_layer.rb +78 -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 +478 -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 +148 -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 +95 -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 +43 -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/tmx_ext/object.rb +26 -0
- data/lib/tmx_ext/tile_set.rb +41 -0
- data/metro.gemspec +57 -0
- data/metro.png +0 -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/image_spec.rb +33 -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/units/rectangle_bounds_spec.rb +56 -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
- data/spec/tmx_ext/object_spec.rb +96 -0
- data/spec/tmx_ext/tile_set_spec.rb +24 -0
- metadata +379 -0
data/lib/metro/image.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
#
|
4
|
+
# Image is a wrapper class for a Gosu Image. This allows for additional data
|
5
|
+
# to be stored without relying on monkey-patching on functionality.
|
6
|
+
#
|
7
|
+
class Image < SimpleDelegator
|
8
|
+
|
9
|
+
def initialize(gosu_image,path,tileable)
|
10
|
+
super(gosu_image)
|
11
|
+
@path = path
|
12
|
+
@tileable = tileable
|
13
|
+
end
|
14
|
+
|
15
|
+
# The relative path of the image
|
16
|
+
attr_reader :path
|
17
|
+
|
18
|
+
# The tileability of the image
|
19
|
+
attr_reader :tileable
|
20
|
+
|
21
|
+
def dimensions
|
22
|
+
Metro::Units::Dimensions.of width, height
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Finds an existing image or creates a new image given the window, path,
|
27
|
+
# and tileablilty.
|
28
|
+
#
|
29
|
+
# @example Finding or creating an Image
|
30
|
+
#
|
31
|
+
# Metro::Image.find_or_create window: model.window,
|
32
|
+
# path: "asset_path", tileable: tileable
|
33
|
+
#
|
34
|
+
def self.find_or_create(options)
|
35
|
+
path = AssetPath.with(options[:path])
|
36
|
+
images[path.to_s] or (images[path.to_s] = create(options))
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Create an image given the window, path, and tileability.
|
41
|
+
#
|
42
|
+
# @example Creating an Image
|
43
|
+
#
|
44
|
+
# Metro::Image.create window: model.window,
|
45
|
+
# path: "asset_path", tileable: tileable
|
46
|
+
#
|
47
|
+
def self.create(options)
|
48
|
+
window, asset_path, tileable = create_params(options)
|
49
|
+
gosu_image = Gosu::Image.new(window,asset_path.filepath,tileable)
|
50
|
+
new gosu_image, asset_path.path, tileable
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.crop(window,image,bounds)
|
54
|
+
cropped_image = TexPlay.create_image(window,bounds.width,bounds.height)
|
55
|
+
cropped_image.refresh_cache
|
56
|
+
cropped_image.splice image, 0, 0, crop: [ bounds.left, bounds.top, bounds.right, bounds.bottom ]
|
57
|
+
cropped_image
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.create_params(options)
|
63
|
+
options.symbolize_keys!
|
64
|
+
asset_path = AssetPath.with(options[:path])
|
65
|
+
window = options[:window]
|
66
|
+
tileable = !!options[:tileable]
|
67
|
+
[ window, asset_path, tileable ]
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.images
|
71
|
+
@images ||= {}
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Generates a default logger to standard out that can be used within Metro or the game.
|
4
|
+
#
|
5
|
+
# @example Outputting information at the debug level
|
6
|
+
#
|
7
|
+
# log.debug "The the screen resolution is #{Game.width},#{Game.height}"
|
8
|
+
#
|
9
|
+
def log
|
10
|
+
@log ||= begin
|
11
|
+
logger = Logger.new(STDOUT)
|
12
|
+
logger.level = Logger::DEBUG
|
13
|
+
logger
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Display an error message defined within the localization file. A game error displays
|
19
|
+
# a error title, message, and actions that can be taken to possibly address this issue.
|
20
|
+
#
|
21
|
+
# @param [String] message the I18n string found in the locale file.
|
22
|
+
# @param [Hash] details contains all the possible key-value pairs that might be needed
|
23
|
+
# for the localized error messages.
|
24
|
+
#
|
25
|
+
def error!(messages, details = {})
|
26
|
+
details = { show: true, exit: true }.merge details
|
27
|
+
|
28
|
+
message = TemplateMessage.new messages: messages, details: details,
|
29
|
+
website: Game.website, contact: Game.contact
|
30
|
+
|
31
|
+
warn message if details[:show]
|
32
|
+
exit 1 if details[:exit]
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Metro
|
2
|
+
class MissingScene < Scene
|
3
|
+
scene_name :missing_scene
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :missing_scene
|
7
|
+
end
|
8
|
+
|
9
|
+
draw :title, text: "Missing Scene!",
|
10
|
+
position: "20,20,1",
|
11
|
+
color: "rgb(255,0,0)",
|
12
|
+
font: {size: 80},
|
13
|
+
model: "metro::ui::label"
|
14
|
+
|
15
|
+
draw :message, text: 'The scene `#{self.class.missing_scene}` was requested, but is missing!',
|
16
|
+
position: "20,100,1",
|
17
|
+
color: "rgb(255,255,255)",
|
18
|
+
model: "metro::ui::label"
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Metro
|
2
|
+
module Audio
|
3
|
+
|
4
|
+
#
|
5
|
+
# A song represents an audio representation.
|
6
|
+
#
|
7
|
+
class Song < Metro::Model
|
8
|
+
|
9
|
+
property :song
|
10
|
+
property :volume, default: 1.0
|
11
|
+
property :state, type: :text, default: 'play'
|
12
|
+
|
13
|
+
def show
|
14
|
+
song.volume = self.volume
|
15
|
+
play if state == "play"
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop
|
19
|
+
song.stop
|
20
|
+
end
|
21
|
+
|
22
|
+
def play
|
23
|
+
song.play if not song.playing? and not song.paused?
|
24
|
+
end
|
25
|
+
|
26
|
+
def pause
|
27
|
+
song.playing? ? song.pause : song.play
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative 'model_factory'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
module Draws
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
#
|
13
|
+
# Define an actor with the given name and options.
|
14
|
+
#
|
15
|
+
# As a convenience the draw method will define `getter` and `setter`
|
16
|
+
# methods for the specified actor.
|
17
|
+
#
|
18
|
+
# @example Defining a title label within a scene
|
19
|
+
#
|
20
|
+
# class ExampleScene
|
21
|
+
# draw :title, text: 'Title Screen',
|
22
|
+
# model: 'metro::ui::label'
|
23
|
+
# position: '20,20,0',
|
24
|
+
# scale: '3,3',
|
25
|
+
# color: 'rgba(255,255,255,1.0)'
|
26
|
+
#
|
27
|
+
# def show
|
28
|
+
# puts "Where is my title? #{title.x},#{title.y}"
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
def draw(actor_name,options = {})
|
33
|
+
|
34
|
+
view_content_for_actor = view.content[actor_name.to_s]
|
35
|
+
|
36
|
+
actor_data = view_content_for_actor.merge(options)
|
37
|
+
actor_data[:name] = actor_name
|
38
|
+
|
39
|
+
scene_actor = ModelFactory.new actor_name, actor_data
|
40
|
+
|
41
|
+
define_method actor_name do
|
42
|
+
instance_variable_get("@#{actor_name}")
|
43
|
+
end
|
44
|
+
|
45
|
+
define_method "#{actor_name}=" do |value|
|
46
|
+
instance_variable_set("@#{actor_name}",value)
|
47
|
+
end
|
48
|
+
|
49
|
+
drawings.push scene_actor
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Define a sound actor with the given anem and options.
|
54
|
+
#
|
55
|
+
# @see #draw
|
56
|
+
#
|
57
|
+
def play(song_name,options={})
|
58
|
+
draw song_name, options.merge(model: "metro::audio::song")
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Define several actors to be drawn.
|
63
|
+
#
|
64
|
+
def draws(*actor_names)
|
65
|
+
actor_names = actor_names.flatten.compact
|
66
|
+
|
67
|
+
actor_names.each do |actor_name|
|
68
|
+
draw actor_name
|
69
|
+
end
|
70
|
+
|
71
|
+
drawings
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# All of the model factories that have been defined.
|
76
|
+
#
|
77
|
+
def drawings
|
78
|
+
@drawings ||= []
|
79
|
+
end
|
80
|
+
|
81
|
+
alias_method :actors, :drawings
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
#
|
4
|
+
# Key-Value coding emulates the functionality found in Objective-C, which allows
|
5
|
+
# for an object to be sent a message which contains the method to return. This is
|
6
|
+
# the same as Ruby. However, Objective-C also supports the use of the dot notation
|
7
|
+
# within the keys to acces the sub-values.
|
8
|
+
#
|
9
|
+
# @example Setting the red value of the color on a Model.
|
10
|
+
#
|
11
|
+
# class Elf
|
12
|
+
# include KeyValueCoding
|
13
|
+
#
|
14
|
+
# attr_accessor :color
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# elf = Elf.new
|
18
|
+
# elf.color = Gosu::Color.new "rgb(0,0,0)"
|
19
|
+
#
|
20
|
+
# elf.get("color.red") # => 0
|
21
|
+
# elf.set("color.red",255)
|
22
|
+
# elf.get("color.red") # => 255
|
23
|
+
#
|
24
|
+
module KeyValueCoding
|
25
|
+
|
26
|
+
def set(name,value)
|
27
|
+
keys = name.to_s.split('.')
|
28
|
+
key_to_set = keys[0..-2].inject(self) {|target,method| target.send(method) }
|
29
|
+
key_to_set.send("#{keys.last}=",value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(name)
|
33
|
+
keys = name.to_s.split('.')
|
34
|
+
keys.inject(self) {|target,method| target.send(method) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require_relative 'key_value_coding'
|
2
|
+
require_relative 'properties/property'
|
3
|
+
require_relative 'models'
|
4
|
+
|
5
|
+
module Metro
|
6
|
+
|
7
|
+
#
|
8
|
+
# The Model is a basic, generic representation of a game object
|
9
|
+
# that has a visual representation within the scene's window.
|
10
|
+
#
|
11
|
+
# Model is designed to be an abstract class, to be subclassed by
|
12
|
+
# other models.
|
13
|
+
#
|
14
|
+
# @see Models::Generic
|
15
|
+
#
|
16
|
+
class Model
|
17
|
+
include PropertyOwner
|
18
|
+
include Units
|
19
|
+
|
20
|
+
#
|
21
|
+
# This is an entry point for customization. As the model's {#initialize}
|
22
|
+
# method performs may perform some initialization that may be necessary.
|
23
|
+
#
|
24
|
+
# At this point the model has been created. However, the window and scene
|
25
|
+
# of the model will not have been defined and defined properties rely on
|
26
|
+
# the window or scene will return nil values. Other properties also will
|
27
|
+
# likely not be set.
|
28
|
+
#
|
29
|
+
# @note This method should be implemented in the Model subclass.
|
30
|
+
#
|
31
|
+
def after_initialize ; end
|
32
|
+
|
33
|
+
#
|
34
|
+
# This is an entry point for customization. After the model's properties
|
35
|
+
# have been set and the model has been assigned to the window and scene
|
36
|
+
# this method is called. Here is where customization of properties or
|
37
|
+
# final positioning can be performed.
|
38
|
+
#
|
39
|
+
# @note This method may be implemented in the Model subclass.
|
40
|
+
#
|
41
|
+
def show ; end
|
42
|
+
|
43
|
+
#
|
44
|
+
# This is called every update interval while the actor is in the scene
|
45
|
+
#
|
46
|
+
# @note This method should be implemented in the Model subclass
|
47
|
+
#
|
48
|
+
def update ; end
|
49
|
+
|
50
|
+
#
|
51
|
+
# This is called after an update. A model normally is not removed after
|
52
|
+
# an update, however if the model responds true to #update_completed? then it
|
53
|
+
# will be removed.
|
54
|
+
#
|
55
|
+
# @note This method should be implemented in the Model sublclass if you
|
56
|
+
# are interested in having the model be removed from the scene.
|
57
|
+
#
|
58
|
+
def update_completed? ; false ; end
|
59
|
+
|
60
|
+
#
|
61
|
+
# This is called after every {#update} and when the OS wants the window to
|
62
|
+
# repaint itself.
|
63
|
+
#
|
64
|
+
# @note This method should be implemented in the Model subclass.
|
65
|
+
#
|
66
|
+
def draw ; end
|
67
|
+
|
68
|
+
#
|
69
|
+
# This is called after a draw. A model normally is not removed after
|
70
|
+
# a draw, however if the model responds true to #draw_completed? then it
|
71
|
+
# will be removed.
|
72
|
+
#
|
73
|
+
# @note This method should be implemented in the Model sublclass if you
|
74
|
+
# are interested in having the model be removed from the scene.
|
75
|
+
#
|
76
|
+
def draw_completed? ; false ; end
|
77
|
+
|
78
|
+
def self.model_name(model_name=nil)
|
79
|
+
@model_name ||= to_s.underscore
|
80
|
+
model_name ? @model_name = model_name.to_s : @model_name
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# @return [String] the name of the model class.
|
85
|
+
#
|
86
|
+
property :model, type: :text
|
87
|
+
|
88
|
+
#
|
89
|
+
# @return [String] the name of model as it is used within the view or the scene.
|
90
|
+
# This is the common name, the key within the view file, or the name symbol
|
91
|
+
# name specified in the scene.
|
92
|
+
#
|
93
|
+
property :name, type: :text
|
94
|
+
|
95
|
+
#
|
96
|
+
# @return [TrueClass,FalseClass] true if the model should be saved to the
|
97
|
+
# view file, false when the model should not be savedable to the view file.
|
98
|
+
#
|
99
|
+
property :saveable_to_view, type: :boolean, default: true
|
100
|
+
|
101
|
+
#
|
102
|
+
# The window that this model that this window is currently being
|
103
|
+
# displayed.
|
104
|
+
#
|
105
|
+
# The current value of window is managed by the scene
|
106
|
+
# as this is set when the Scene is added to the window. All the
|
107
|
+
# models gain access to the window.
|
108
|
+
#
|
109
|
+
# @see Window
|
110
|
+
#
|
111
|
+
attr_accessor :window
|
112
|
+
|
113
|
+
#
|
114
|
+
# The scene that this model is currently being displayed.
|
115
|
+
#
|
116
|
+
# The current value of scene is managed by the scene as this
|
117
|
+
# is set when the scene is created.
|
118
|
+
#
|
119
|
+
# @see Scene
|
120
|
+
attr_accessor :scene
|
121
|
+
|
122
|
+
include KeyValueCoding
|
123
|
+
|
124
|
+
#
|
125
|
+
# Generate a custom notification event with the given name.
|
126
|
+
#
|
127
|
+
# @param [Symbol] event the name of the notification to generate.
|
128
|
+
#
|
129
|
+
def notification(event)
|
130
|
+
scene.notification(event.to_sym,self)
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Allows for the definition of events within the scene.
|
135
|
+
#
|
136
|
+
include HasEvents
|
137
|
+
|
138
|
+
#
|
139
|
+
# A helper method that allows the current model to generate another model. This
|
140
|
+
# is useful as it allows for the current model to pass window and scene state
|
141
|
+
# to the created model.
|
142
|
+
#
|
143
|
+
# @param [String] model_name the name of the model to be created.
|
144
|
+
# @return [Metro::Model] the metro model instance
|
145
|
+
#
|
146
|
+
def create(model_name,options={})
|
147
|
+
# @TODO: this is another path that parallels the ModelFactory
|
148
|
+
model_class = Metro::Models.find(model_name)
|
149
|
+
mc = model_class.new options
|
150
|
+
mc.scene = scene
|
151
|
+
mc.window = window
|
152
|
+
mc
|
153
|
+
end
|
154
|
+
|
155
|
+
#
|
156
|
+
# By default a model has no bounds. Each subclass of model will have to
|
157
|
+
# define how their bounds are defined.
|
158
|
+
#
|
159
|
+
def bounds
|
160
|
+
Bounds.none
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Create an instance of a model.
|
165
|
+
#
|
166
|
+
# @note Overridding initialize method should be avoided, using the {#aftter_initialize)
|
167
|
+
# method or done with care to ensure that functionality is preserved.
|
168
|
+
#
|
169
|
+
def initialize(options = {})
|
170
|
+
_load(options)
|
171
|
+
after_initialize
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# Loads a hash of content into the model. This process will convert the hash
|
176
|
+
# of content into setter and getter methods with appropriate ruby style names.
|
177
|
+
#
|
178
|
+
# This is used internally when the model is created for the Scene. It is loaded
|
179
|
+
# with the contents of the view.
|
180
|
+
#
|
181
|
+
def _load(options = {})
|
182
|
+
# Clean up and symbolize all the keys then merge that with the existing properties
|
183
|
+
options.keys.each do |key|
|
184
|
+
property_name = key.to_s.underscore.to_sym
|
185
|
+
if respond_to? "#{property_name}="
|
186
|
+
send("#{property_name}=",options.delete(key))
|
187
|
+
else
|
188
|
+
options[property_name] = options.delete(key)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
properties.merge! options
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
# Generate a hash export of all the fields that were previously stored within
|
197
|
+
# the model.
|
198
|
+
#
|
199
|
+
# This is used internally within the scene to transfer the data from one model
|
200
|
+
# to another model.
|
201
|
+
#
|
202
|
+
def _save
|
203
|
+
properties
|
204
|
+
end
|
205
|
+
|
206
|
+
#
|
207
|
+
# Generate a hash representation of the model.
|
208
|
+
#
|
209
|
+
def to_hash
|
210
|
+
{ name => properties.except(:name) }
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# @return a common name that can be used through the system as a common identifier.
|
215
|
+
#
|
216
|
+
def self.metro_name
|
217
|
+
name.underscore
|
218
|
+
end
|
219
|
+
|
220
|
+
#
|
221
|
+
# @return an array of all ancestor models by name
|
222
|
+
#
|
223
|
+
def self.hierarchy
|
224
|
+
ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# Captures all classes that subclass Model.
|
229
|
+
#
|
230
|
+
def self.inherited(base)
|
231
|
+
models << base.to_s
|
232
|
+
Models.add(base)
|
233
|
+
end
|
234
|
+
|
235
|
+
#
|
236
|
+
# All subclasses of Model, this should be all the defined
|
237
|
+
#
|
238
|
+
def self.models
|
239
|
+
@models ||= []
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
require_relative 'ui/ui'
|
246
|
+
require_relative 'audio/song'
|