metro 0.1.5 → 0.1.6
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/README.md +19 -0
- data/changelog.md +8 -0
- data/lib/assets/missing_animation.png +0 -0
- data/lib/commands/generate_model.rb +2 -2
- data/lib/commands/generate_scene.rb +12 -2
- data/lib/commands/generate_view.rb +1 -1
- data/lib/gosu_ext/color.rb +1 -1
- data/lib/gosu_ext/image.rb +5 -0
- data/lib/metro.rb +18 -5
- data/lib/metro/animation/animation.rb +31 -0
- data/lib/metro/asset_path.rb +9 -0
- data/lib/metro/events/event_dictionary.rb +53 -0
- data/lib/metro/events/event_factory.rb +5 -3
- data/lib/metro/events/has_events.rb +5 -6
- data/lib/metro/game.rb +1 -1
- data/lib/metro/models/dimensions.rb +21 -0
- data/lib/metro/models/model.rb +149 -52
- data/lib/metro/models/model_factory.rb +4 -5
- data/lib/metro/models/{generic.rb → models/generic.rb} +0 -0
- data/lib/metro/models/{grid_drawer.rb → models/grid_drawer.rb} +4 -9
- data/lib/metro/models/{image.rb → models/image.rb} +11 -14
- data/lib/metro/models/models/label.rb +44 -0
- data/lib/metro/models/{menu.rb → models/menu.rb} +23 -18
- data/lib/metro/models/{rectangle.rb → models/rectangle.rb} +6 -5
- data/lib/metro/models/point.rb +23 -0
- data/lib/metro/models/properties/angle.rb +43 -0
- data/lib/metro/models/properties/animation.rb +143 -0
- data/lib/metro/models/properties/color.rb +113 -0
- data/lib/metro/models/properties/dimensions.rb +66 -0
- data/lib/metro/models/properties/font.rb +155 -0
- data/lib/metro/models/properties/image.rb +101 -0
- data/lib/metro/models/properties/numeric.rb +29 -0
- data/lib/metro/models/properties/position.rb +84 -0
- data/lib/metro/models/properties/property.rb +111 -0
- data/lib/metro/models/properties/scale.rb +89 -0
- data/lib/metro/models/properties/text.rb +66 -0
- data/lib/metro/models/properties/velocity.rb +80 -0
- data/lib/metro/models/scale.rb +21 -0
- data/lib/metro/scene.rb +19 -1
- data/lib/metro/scenes.rb +91 -31
- data/lib/metro/transitions/scene_transitions.rb +8 -0
- data/lib/metro/version.rb +1 -1
- data/lib/metro/views/view.rb +9 -1
- data/lib/templates/game/metro.tt +1 -1
- data/lib/templates/game/models/game_model.rb +3 -0
- data/lib/templates/game/scenes/brand_scene.rb +1 -1
- data/lib/templates/game/scenes/brand_to_title_scene.rb +1 -1
- data/lib/templates/game/scenes/game_scene.rb +19 -0
- data/lib/templates/game/scenes/title_scene.rb +1 -1
- data/lib/templates/game/views/brand_to_title.yaml +2 -2
- data/lib/templates/game/views/title.yaml +3 -3
- data/lib/templates/{model.rb.erb → model.rb.tt} +1 -1
- data/lib/templates/{scene.rb.erb → scene.rb.tt} +1 -1
- data/lib/templates/view.yaml.tt +6 -0
- data/spec/metro/models/models/label_spec.rb +110 -0
- data/spec/metro/models/properties/color_spec.rb +85 -0
- data/spec/metro/models/properties/font_spec.rb +129 -0
- data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
- data/spec/metro/models/properties/position_property_spec.rb +90 -0
- data/spec/metro/scenes_spec.rb +77 -0
- metadata +50 -16
- data/lib/metro/models/label.rb +0 -63
- data/lib/templates/view.yaml.erb +0 -32
data/README.md
CHANGED
@@ -53,3 +53,22 @@ $ metro generate scene first
|
|
53
53
|
```
|
54
54
|
|
55
55
|
This should generate a scene in the scenes directory. The scene file contains a lot of examples of how to draw, animate and have your scene listen to events.
|
56
|
+
|
57
|
+
|
58
|
+
### Resources
|
59
|
+
|
60
|
+
#### Art
|
61
|
+
|
62
|
+
* [Lost Garden](http://www.lostgarden.com/2007/05/dancs-miraculously-flexible-game.html)
|
63
|
+
|
64
|
+
#### Books
|
65
|
+
|
66
|
+
* [Rules of Play](http://www.amazon.com/dp/0262240459)
|
67
|
+
* [Game Programming Gems 8](http://www.amazon.com/dp/1584507020)
|
68
|
+
* [Game Feel](http://www.amazon.com/dp/0123743281)
|
69
|
+
* [Game Coding Complete](http://www.amazon.com/dp/1584506806)
|
70
|
+
* [Game Design Workshop](http://www.amazon.com/dp/0240809742)
|
71
|
+
* [Challenges For Game Designers](http://www.amazon.com/dp/158450580X)
|
72
|
+
* [The Art of Game Design: A book of lenses](http://www.amazon.com/dp/0123694965)
|
73
|
+
* [A Theory of Fun](http://www.theoryoffun.com)
|
74
|
+
* [Andrew Rollings and Ernest Adams on Game Design](http://www.amazon.com/dp/1592730019)
|
data/changelog.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Metro
|
2
2
|
|
3
|
+
## 0.1.6 / 2012-11-07
|
4
|
+
|
5
|
+
* Events are shared from superclasses to subclases.
|
6
|
+
* Templates updated to use GameScene and GameModel for each game.
|
7
|
+
* Models are automatically added to the update loop
|
8
|
+
* Model properties now make it easier to store/retrieve various
|
9
|
+
common numeric, position font, image, and animation properties.
|
10
|
+
|
3
11
|
## 0.1.5 / 2012-11-01
|
4
12
|
|
5
13
|
* Metro.reload! will reload all game classes
|
Binary file
|
@@ -9,7 +9,7 @@ module Metro
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def model_name
|
12
|
-
name.
|
12
|
+
name.camelize
|
13
13
|
end
|
14
14
|
|
15
15
|
end
|
@@ -17,7 +17,7 @@ module Metro
|
|
17
17
|
argument :name
|
18
18
|
|
19
19
|
def create_model_file
|
20
|
-
template "model.rb.
|
20
|
+
template "model.rb.tt", "models/#{model_filename}.rb"
|
21
21
|
end
|
22
22
|
|
23
23
|
end
|
@@ -11,7 +11,12 @@ module Metro
|
|
11
11
|
|
12
12
|
def scene_class_name
|
13
13
|
scene_name = name.gsub(/_?Scene$/i,'')
|
14
|
-
"#{scene_name.
|
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
|
15
20
|
end
|
16
21
|
|
17
22
|
end
|
@@ -19,8 +24,13 @@ module Metro
|
|
19
24
|
argument :name
|
20
25
|
|
21
26
|
def create_scene_file
|
22
|
-
template "scene.rb.
|
27
|
+
template "scene.rb.tt", "scenes/#{scene_filename}.rb"
|
23
28
|
end
|
29
|
+
|
30
|
+
def create_view_file
|
31
|
+
template "view.yaml.tt", "views/#{view_filename}.yaml"
|
32
|
+
end
|
33
|
+
|
24
34
|
end
|
25
35
|
|
26
36
|
end
|
data/lib/gosu_ext/color.rb
CHANGED
@@ -26,7 +26,7 @@ class Gosu::Color
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.parse_rgba(rgba)
|
29
|
-
if rgba =~ /rgba\(([\d]{1,3}),([\d]{1,3}),([\d]{1,3}),(\d(?:\.\d)?)\)/
|
29
|
+
if rgba =~ /rgba\(([\d]{1,3}(?:\.\d*)?),([\d]{1,3}(?:\.\d*)?),([\d]{1,3}(?:\.\d*)?),(\d(?:\.\d*)?)\)/
|
30
30
|
[ (255 * $4.to_f).floor.to_i, $1.to_i, $2.to_i, $3.to_i ]
|
31
31
|
end
|
32
32
|
end
|
data/lib/metro.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'gosu'
|
2
2
|
require 'gosu_ext/color'
|
3
|
+
require 'gosu_ext/image'
|
3
4
|
require 'gosu_ext/gosu_constants'
|
4
5
|
require 'i18n'
|
5
6
|
require 'active_support'
|
6
7
|
require 'active_support/dependencies'
|
7
8
|
require 'active_support/inflector'
|
9
|
+
require 'active_support/core_ext/hash'
|
10
|
+
require 'active_support/hash_with_indifferent_access'
|
8
11
|
|
9
12
|
require 'core_ext/numeric'
|
10
13
|
require 'logger'
|
@@ -12,6 +15,9 @@ require 'erb'
|
|
12
15
|
|
13
16
|
require 'locale/locale'
|
14
17
|
require 'metro/asset_path'
|
18
|
+
require 'metro/models/point'
|
19
|
+
require 'metro/models/scale'
|
20
|
+
require 'metro/models/dimensions'
|
15
21
|
require 'metro/logging'
|
16
22
|
require 'metro/version'
|
17
23
|
require 'metro/template_message'
|
@@ -20,7 +26,6 @@ require 'metro/game'
|
|
20
26
|
require 'metro/scene'
|
21
27
|
require 'metro/scenes'
|
22
28
|
require 'metro/models/model'
|
23
|
-
require 'metro/models/generic'
|
24
29
|
|
25
30
|
require_relative 'metro/missing_scene'
|
26
31
|
|
@@ -41,6 +46,10 @@ module Metro
|
|
41
46
|
'metro'
|
42
47
|
end
|
43
48
|
|
49
|
+
def asset_dir
|
50
|
+
File.join File.dirname(__FILE__), "assets"
|
51
|
+
end
|
52
|
+
|
44
53
|
#
|
45
54
|
# Run will load the contents of the game contents and game files
|
46
55
|
# within the current working directory and start the game. By default
|
@@ -58,6 +67,7 @@ module Metro
|
|
58
67
|
end
|
59
68
|
|
60
69
|
def load_game_files!
|
70
|
+
EventDictionary.reset!
|
61
71
|
prepare_watcher!
|
62
72
|
load_game_files
|
63
73
|
execute_watcher!
|
@@ -104,18 +114,21 @@ module Metro
|
|
104
114
|
|
105
115
|
def load_game_files
|
106
116
|
$LOAD_PATH.unshift(Dir.pwd) unless $LOAD_PATH.include?(Dir.pwd)
|
107
|
-
load_paths '
|
117
|
+
load_paths 'lib'
|
118
|
+
load_path 'scenes', prioritize: 'game_scene.rb'
|
119
|
+
load_path 'models', prioritize: 'game_model.rb'
|
108
120
|
end
|
109
121
|
|
110
122
|
def load_paths(*paths)
|
111
123
|
paths.flatten.compact.each {|path| load_path path }
|
112
124
|
end
|
113
125
|
|
114
|
-
def load_path(path)
|
115
|
-
Dir["#{path}/**/*.rb"]
|
126
|
+
def load_path(path,options = {})
|
127
|
+
files = Dir["#{path}/**/*.rb"]
|
128
|
+
files.sort! {|file| File.basename(file) == options[:prioritize] ? -1 : 1 }
|
129
|
+
files.each {|model| require_or_load model }
|
116
130
|
end
|
117
131
|
|
118
|
-
|
119
132
|
def load_game_configuration(filename)
|
120
133
|
gamefile = File.basename(filename)
|
121
134
|
game_files_exist!(gamefile)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Metro
|
2
|
+
|
3
|
+
#
|
4
|
+
# The animation is an wrapper object for an array of Gosu::Images that also contains
|
5
|
+
# the additional information on the path, height, width, and tileability.
|
6
|
+
#
|
7
|
+
class Animation
|
8
|
+
|
9
|
+
attr_accessor :images, :path, :height, :width, :tileable
|
10
|
+
|
11
|
+
def initialize(params = {})
|
12
|
+
@images = Array(params[:images])
|
13
|
+
@path = params[:path]
|
14
|
+
@height = params[:height]
|
15
|
+
@width = params[:width]
|
16
|
+
@tileable = params[:tileable]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
{ path: path, width: width.to_i, height: height.to_i, tileable: !!tileable }
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# @return a Gosu::Image to be displayed in a animation sequence.
|
25
|
+
#
|
26
|
+
def image
|
27
|
+
images[Gosu::milliseconds / 100 % images.size]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/metro/asset_path.rb
CHANGED
@@ -20,3 +20,12 @@
|
|
20
20
|
def asset_path(name)
|
21
21
|
File.join Dir.pwd, "assets", name
|
22
22
|
end
|
23
|
+
|
24
|
+
|
25
|
+
#
|
26
|
+
# The metro_asset_path is a helper which will generate a filepath based on the directory
|
27
|
+
# of the metro library. This is used to retrieve assets internally for missing images.
|
28
|
+
#
|
29
|
+
def metro_asset_path(name)
|
30
|
+
File.join Metro.asset_dir, name
|
31
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'event_factory'
|
2
|
+
|
3
|
+
module Metro
|
4
|
+
|
5
|
+
module EventDictionary
|
6
|
+
extend self
|
7
|
+
|
8
|
+
#
|
9
|
+
# All defined events within this dictionary.
|
10
|
+
#
|
11
|
+
def events
|
12
|
+
@events ||= Hash.new
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# @example Adding a new SceneEvent to the Dictionary
|
17
|
+
#
|
18
|
+
# SceneEventDictionary.add target: scene_name, type: event_type, args: args, block: block
|
19
|
+
#
|
20
|
+
def add(params = {})
|
21
|
+
target = params[:target]
|
22
|
+
event = EventFactory.new params[:type], params[:args], ¶ms[:block]
|
23
|
+
events[target] = events_for_target(target).push event
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Return all the events for all the specified targets.
|
28
|
+
#
|
29
|
+
def events_for_targets(*list)
|
30
|
+
found_events = Array(list).flatten.compact.map {|s| events_for_target(s) }.flatten.compact
|
31
|
+
log.debug "Retrieved (#{found_events.count}) events for [#{list.join(",")}]"
|
32
|
+
found_events
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Return the events for the specified target
|
37
|
+
#
|
38
|
+
def events_for_target(scene_name)
|
39
|
+
events[scene_name] ||= []
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# When the game is reset the event dictionary needs to flush out all of the events that it
|
44
|
+
# has loaded as the game files will be reloaded. All metro related components will not
|
45
|
+
# be removed as those files are not reloaded when the game is reloaded.
|
46
|
+
#
|
47
|
+
def reset!
|
48
|
+
events.delete_if { |name,events| ! name.start_with? "metro/" }
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -2,11 +2,13 @@ module Metro
|
|
2
2
|
|
3
3
|
class EventFactory
|
4
4
|
|
5
|
-
attr_reader :event, :
|
5
|
+
attr_reader :event, :args, :block
|
6
6
|
|
7
|
-
|
7
|
+
alias_method :buttons, :args
|
8
|
+
|
9
|
+
def initialize(event,args=[],&block)
|
8
10
|
@event = event
|
9
|
-
@
|
11
|
+
@args = args
|
10
12
|
@block = block
|
11
13
|
end
|
12
14
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'event_dictionary'
|
2
2
|
|
3
3
|
module Metro
|
4
4
|
|
@@ -90,16 +90,15 @@ module Metro
|
|
90
90
|
# This example uses a block instead of a method name but it is absolultey the same
|
91
91
|
# as the last example.
|
92
92
|
#
|
93
|
-
def event(event_type,*
|
94
|
-
|
95
|
-
events.push scene_event
|
93
|
+
def event(event_type,*args,&block)
|
94
|
+
EventDictionary.add target: metro_name, type: event_type, args: args, block: block
|
96
95
|
end
|
97
96
|
|
98
97
|
#
|
99
|
-
# @return a list of all the EventFactories defined for
|
98
|
+
# @return a list of all the EventFactories defined for this event holding object
|
100
99
|
#
|
101
100
|
def events
|
102
|
-
|
101
|
+
EventDictionary.events_for_targets(hierarchy)
|
103
102
|
end
|
104
103
|
|
105
104
|
end
|
data/lib/metro/game.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Metro
|
2
|
+
class Dimensions < Struct.new(:width,:height)
|
3
|
+
|
4
|
+
def self.none
|
5
|
+
new 0.0, 0.0
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.of(width,height)
|
9
|
+
new width.to_f, height.to_f
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.parse(string)
|
13
|
+
to *string.split(",",2).map(&:to_f)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"#{width},#{height}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/metro/models/model.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'key_value_coding'
|
2
2
|
require_relative 'rectangle_bounds'
|
3
|
+
require_relative 'properties/property'
|
3
4
|
|
4
5
|
module Metro
|
5
6
|
|
@@ -14,6 +15,120 @@ module Metro
|
|
14
15
|
#
|
15
16
|
class Model
|
16
17
|
|
18
|
+
#
|
19
|
+
# This is called every update interval while the actor is in the scene
|
20
|
+
#
|
21
|
+
# @note This method should be implemented in the Model subclass
|
22
|
+
#
|
23
|
+
def update ; end
|
24
|
+
|
25
|
+
#
|
26
|
+
# This is called after an update. A model normally is not removed after
|
27
|
+
# an update, however if the model responds true to #completed? then it
|
28
|
+
# will be removed.
|
29
|
+
#
|
30
|
+
# @note This method should be implemented in the Model sublclass if you
|
31
|
+
# are interested in having the model be removed from the scene.
|
32
|
+
#
|
33
|
+
def completed? ; false ; end
|
34
|
+
|
35
|
+
|
36
|
+
def self.property(name,options={})
|
37
|
+
|
38
|
+
# Use the name as the property type if one has not been provided.
|
39
|
+
|
40
|
+
property_type = options[:type] || name
|
41
|
+
|
42
|
+
property_class = Property.property(property_type)
|
43
|
+
|
44
|
+
# When the name does not match the property type then we want to force
|
45
|
+
# the prefixing to be on for our sub-properties. This is to make sure
|
46
|
+
# that when people define multiple fonts and colors that they do not
|
47
|
+
# overlap.
|
48
|
+
|
49
|
+
override_prefix = !(name == property_type)
|
50
|
+
|
51
|
+
# Define any properties defined on this property
|
52
|
+
|
53
|
+
property_class.defined_properties.each do |subproperty|
|
54
|
+
sub_options = { prefix: override_prefix }.merge(subproperty.options)
|
55
|
+
sub_options = sub_options.merge(parents: (Array(sub_options[:parents]) + [name]))
|
56
|
+
|
57
|
+
property subproperty.name, sub_options
|
58
|
+
end
|
59
|
+
|
60
|
+
# To ensure that our sub-properties are aware of the of their
|
61
|
+
# parent property for which they are dependent on we will need
|
62
|
+
# to know this information because we need to behave appropriately
|
63
|
+
# within the getter and setter blocks below.
|
64
|
+
|
65
|
+
is_a_dependency = true if options[:parents]
|
66
|
+
|
67
|
+
if is_a_dependency
|
68
|
+
|
69
|
+
parents = Array(options[:parents])
|
70
|
+
|
71
|
+
method_name = name
|
72
|
+
|
73
|
+
if options[:prefix]
|
74
|
+
method_name = (parents + [name]).join("_")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Define a getter for the sub-property that will traverse the
|
78
|
+
# parent properties, finally returning the filtered value
|
79
|
+
|
80
|
+
define_method method_name do
|
81
|
+
raw_value = (parents + [name]).inject(self) {|current,method| current.send(method) }
|
82
|
+
property_class.new(self,options).get raw_value
|
83
|
+
end
|
84
|
+
|
85
|
+
# Define a setter for the sub-property that will find the parent
|
86
|
+
# value and set itself on that with the filtered value. The parent
|
87
|
+
# is then set.
|
88
|
+
#
|
89
|
+
# @TODO: If getters return dups and not instances of the original object then a very
|
90
|
+
# deep setter will not be valid.
|
91
|
+
#
|
92
|
+
define_method "#{method_name}=" do |value|
|
93
|
+
parent_value = parents.inject(self) {|current,method| current.send(method) }
|
94
|
+
|
95
|
+
prepared_value = property_class.new(self,options).set(value)
|
96
|
+
parent_value.send("#{name}=",prepared_value)
|
97
|
+
|
98
|
+
send("#{parents.last}=",parent_value)
|
99
|
+
end
|
100
|
+
|
101
|
+
else
|
102
|
+
|
103
|
+
define_method name do
|
104
|
+
raw_value = properties[name]
|
105
|
+
property_class.new(self,options).get raw_value
|
106
|
+
end
|
107
|
+
|
108
|
+
define_method "#{name}=" do |value|
|
109
|
+
prepared_value = property_class.new(self,options).set(value)
|
110
|
+
properties[name] = prepared_value
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
def properties
|
118
|
+
@properties ||= {}
|
119
|
+
end
|
120
|
+
|
121
|
+
property :model, type: :text
|
122
|
+
property :name, type: :text
|
123
|
+
|
124
|
+
#
|
125
|
+
# This is called after every {#update} and when the OS wants the window to
|
126
|
+
# repaint itself.
|
127
|
+
#
|
128
|
+
# @note This method should be implemented in the Model subclass.
|
129
|
+
#
|
130
|
+
def draw ; end
|
131
|
+
|
17
132
|
#
|
18
133
|
# The window that this model that this window is currently being
|
19
134
|
# displayed.
|
@@ -59,46 +174,6 @@ module Metro
|
|
59
174
|
#
|
60
175
|
include HasEvents
|
61
176
|
|
62
|
-
#
|
63
|
-
# Returns the color of the model. In most cases where color is a prominent
|
64
|
-
# attribute (e.g. label) this will be the color. In the cases where color
|
65
|
-
# is less promenint (e.g. image) this will likely be a color that can be
|
66
|
-
# used to influence the drawing of it.
|
67
|
-
#
|
68
|
-
# @see #alpha
|
69
|
-
#
|
70
|
-
def color
|
71
|
-
@color
|
72
|
-
end
|
73
|
-
|
74
|
-
#
|
75
|
-
# Sets the color of the model.
|
76
|
-
#
|
77
|
-
# @param [String,Fixnum,Gosu::Color] value the new color to set.
|
78
|
-
#
|
79
|
-
def color=(value)
|
80
|
-
@color = Gosu::Color.new(value)
|
81
|
-
end
|
82
|
-
|
83
|
-
#
|
84
|
-
# @return the alpha value of the model's color. This is an integer value
|
85
|
-
# between 0 and 255.
|
86
|
-
#
|
87
|
-
def alpha
|
88
|
-
color.alpha
|
89
|
-
end
|
90
|
-
|
91
|
-
#
|
92
|
-
# Sets the alpha of the model.
|
93
|
-
#
|
94
|
-
# @param [String,Fixnum] value the new value of the alpha level for the model.
|
95
|
-
# This value should be between 0 and 255.
|
96
|
-
#
|
97
|
-
def alpha=(value)
|
98
|
-
# TODO: coerce the value is between 0 and 255
|
99
|
-
color.alpha = value.to_i
|
100
|
-
end
|
101
|
-
|
102
177
|
def saveable?
|
103
178
|
true
|
104
179
|
end
|
@@ -107,7 +182,7 @@ module Metro
|
|
107
182
|
def contains?(x,y)
|
108
183
|
false
|
109
184
|
end
|
110
|
-
|
185
|
+
|
111
186
|
# Belongs to positionable items only
|
112
187
|
def offset(x,y)
|
113
188
|
self.x += x
|
@@ -121,6 +196,7 @@ module Metro
|
|
121
196
|
# method or done with care to ensure that functionality is preserved.
|
122
197
|
#
|
123
198
|
def initialize(options = {})
|
199
|
+
_load(options)
|
124
200
|
after_initialize
|
125
201
|
end
|
126
202
|
|
@@ -135,22 +211,29 @@ module Metro
|
|
135
211
|
options = {} unless options
|
136
212
|
|
137
213
|
options.each do |raw_key,value|
|
138
|
-
|
139
214
|
key = raw_key.to_s.dup
|
140
215
|
key = key.gsub(/-/,'_').underscore
|
141
216
|
|
217
|
+
|
142
218
|
unless respond_to? key
|
143
|
-
|
144
|
-
|
219
|
+
log.warn "Unknown Property #{key}"
|
220
|
+
self.class.send(:define_method,key) do
|
221
|
+
properties[key]
|
145
222
|
end
|
223
|
+
#raise "Do not know (#{key}) property"
|
146
224
|
end
|
147
225
|
|
148
226
|
unless respond_to? "#{key}="
|
149
|
-
|
150
|
-
|
227
|
+
log.warn "Unknown Property #{key}="
|
228
|
+
self.class.send(:define_method,"#{key}=") do |value|
|
229
|
+
properties[key] = value
|
151
230
|
end
|
231
|
+
|
232
|
+
# raise "Do not know (#{key}=) property"
|
152
233
|
end
|
153
234
|
|
235
|
+
|
236
|
+
|
154
237
|
_loaded_options.push key
|
155
238
|
send "#{key}=", value
|
156
239
|
end
|
@@ -194,6 +277,20 @@ module Metro
|
|
194
277
|
{ name => hash }
|
195
278
|
end
|
196
279
|
|
280
|
+
#
|
281
|
+
# @return a common name that can be used through the system as a common identifier.
|
282
|
+
#
|
283
|
+
def self.metro_name
|
284
|
+
name.underscore
|
285
|
+
end
|
286
|
+
|
287
|
+
#
|
288
|
+
# @return an array of all ancestor models by name
|
289
|
+
#
|
290
|
+
def self.hierarchy
|
291
|
+
ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
|
292
|
+
end
|
293
|
+
|
197
294
|
#
|
198
295
|
# Captures all classes that subclass Model.
|
199
296
|
#
|
@@ -237,9 +334,9 @@ module Metro
|
|
237
334
|
end
|
238
335
|
end
|
239
336
|
|
240
|
-
require_relative 'generic'
|
241
|
-
require_relative 'label'
|
242
|
-
require_relative 'menu'
|
243
|
-
require_relative 'image'
|
244
|
-
require_relative 'rectangle'
|
245
|
-
require_relative 'grid_drawer'
|
337
|
+
require_relative 'models/generic'
|
338
|
+
require_relative 'models/label'
|
339
|
+
require_relative 'models/menu'
|
340
|
+
require_relative 'models/image'
|
341
|
+
require_relative 'models/rectangle'
|
342
|
+
require_relative 'models/grid_drawer'
|