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