metro 0.3.4 → 0.3.5

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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZmI2NDBlMjQ5MzRjZGM4ZTMwZmRkMGJjMDM3NDg2YzUwNGM4NmFmYw==
5
+ data.tar.gz: !binary |-
6
+ N2IwMTFlODhlYzg1ODZkMmU1MzJiNDRkMTQ3Y2Q2ZTc2MWYyMzM5MQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NzI4ZDMyOTBhZTdlOTcwYjgwMWQ3NDJiNWVlZTllNmNlYTY0YWI3ODc5YWNj
10
+ NGMzMmEwODY2YjBlYjkzMTkxZjUyMWJmNDYxYTMxZDlhOWQ2NjQ4OGIxMDBm
11
+ OTEwYTM0OTA3ODExNDVhNGFkYTkxNjFjOWU5MjViZWVkMTYyZmY=
12
+ data.tar.gz: !binary |-
13
+ NjI1ZDY5MDMxNjNkZWU3NzQ5MjBhOTVmMTY2YzM2NWM3MzRmYzY4MWIzYTFj
14
+ NmRmYTBkOGE0OGI5ZWVlZTFhMmE0ZjljYjFhNzNjZjI4N2NlNTI1MGM2MjJl
15
+ OTEwODhiMTI5Y2UyMDYyZDg2NmI1MjYyNmU4NjJkZTdkMzg4N2E=
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in metro.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'chipmunk'
7
+
6
8
  gem 'rake'
7
9
 
8
10
  group 'development' do
data/README.md CHANGED
@@ -1,11 +1,4 @@
1
- ```
2
- ______ ___ _____
3
- ___ |/ /_____ __ /_______________
4
- __ /|_/ / _ _ \_ __/__ ___/_ __ \
5
- _ / / / / __// /_ _ / / /_/ /
6
- /_/ /_/ \___/ \__/ /_/ \____/
7
-
8
- ```
1
+ ![Metro Image](metro.png)
9
2
 
10
3
  Metro is a framework built around [gosu](https://github.com/jlnr/gosu) (the 2D
11
4
  game development library in Ruby). The goal of Metro is to enforce common
@@ -133,19 +126,25 @@ Creating a Game can be done with a single command.
133
126
  $ metro new GAMENAME
134
127
  ```
135
128
 
136
- This should generate for you a starting game with a branding scene and a title
137
- scene. The game allows the player to start the game.
129
+ This should generate for you a starting game with a branding scene, title
130
+ scene and first game scene. The game allows the player to start the game.
138
131
 
139
- The game is missing the `first` scene of the game. This can be created with the
140
- scene generator:
132
+ ## Resources
141
133
 
142
- ```bash
143
- $ metro generate scene first
144
- ```
134
+ ### Metro Documentation
145
135
 
146
- 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.
136
+ The Metro [wiki](../../wiki) contains lots of documentation:
147
137
 
148
- ## Resources
138
+ * [Game Configuration](wiki/game-configuration)
139
+ * [Scenes](../../wiki/scenes)
140
+ * [Views](../../wiki/views)
141
+ * [Animations](../../wiki/animations)
142
+ * [Scene Transitions](../../wiki/transitions)
143
+ * [Models](../../wiki/models)
144
+ * [Metro Models](../../wiki/metro-models)
145
+ * [Model Properties](../../wiki/properties)
146
+ * [Events](../../wiki/events)
147
+ * [Units](../../wiki/units)
149
148
 
150
149
  ### Programming
151
150
 
@@ -155,7 +154,7 @@ This should generate a scene in the scenes directory. The scene file contains a
155
154
  ### Art
156
155
 
157
156
  * [Lost Garden](http://www.lostgarden.com/2007/05/dancs-miraculously-flexible-game.html)
158
- * [TimelieFX](http://www.rigzsoft.co.uk/) particle editor allows you to export animations.
157
+ * [TimelineFX](http://www.rigzsoft.co.uk/) particle editor allows you to export animations.
159
158
  * [Text to ASCII Art Generator](http://patorjk.com/software/taag)
160
159
  * [Icons](http://css-tricks.com/flat-icons-icon-fonts/)
161
160
  * [Subtle Patterns](http://subtlepatterns.com/) various backgrounds and textures.
@@ -175,4 +174,4 @@ This should generate a scene in the scenes directory. The scene file contains a
175
174
  * [Challenges For Game Designers](http://www.amazon.com/dp/158450580X)
176
175
  * [The Art of Game Design: A book of lenses](http://www.amazon.com/dp/0123694965)
177
176
  * [A Theory of Fun](http://www.theoryoffun.com)
178
- * [Andrew Rollings and Ernest Adams on Game Design](http://www.amazon.com/dp/1592730019)
177
+ * [Andrew Rollings and Ernest Adams on Game Design](http://www.amazon.com/dp/1592730019)
data/changelog.md CHANGED
@@ -1,12 +1,16 @@
1
1
  # Metro
2
2
 
3
+ ## 0.3.5 / 2014-08-11
4
+
5
+ * FIX active_support is now activesupport
6
+
3
7
  ## 0.3.4 / 2012-12-14
4
8
 
5
9
  * `metro::ui::sprite` and `metro::ui::animated_sprite` model classes
6
10
  to make it easier to take care of all the basic model attributes.
7
11
  * Event Management changed in the background. The API remains the
8
12
  same.
9
-
13
+
10
14
  ## 0.3.3 / 2012-11-28
11
15
 
12
16
  * Edit Mode - actors within a scene can have their position edited
@@ -56,4 +56,21 @@ class Numeric
56
56
 
57
57
  alias_method :ticks, :tick
58
58
 
59
+ def radians
60
+ self
61
+ end
62
+
63
+ def degrees
64
+ self
65
+ end
66
+
67
+ # Convert the specified numeric value in radians to degrees
68
+ def to_degrees
69
+ self * 180 / Math::PI
70
+ end
71
+
72
+ # Convert the specified numeric value in degrees to radians
73
+ def to_radians
74
+ self * Math::PI / 180
75
+ end
59
76
  end
data/lib/metro.rb CHANGED
@@ -4,6 +4,9 @@ require 'erb'
4
4
  require 'open3'
5
5
 
6
6
  require 'gosu'
7
+ require 'chipmunk'
8
+ require 'texplay'
9
+ require 'tmx'
7
10
  require 'i18n'
8
11
  require 'listen'
9
12
  require 'active_support'
@@ -12,10 +15,12 @@ require 'active_support/inflector'
12
15
  require 'active_support/core_ext/hash'
13
16
  require 'active_support/hash_with_indifferent_access'
14
17
 
15
- require 'gosu_ext/color'
16
- require 'gosu_ext/gosu_constants'
17
18
  require 'core_ext/numeric'
18
19
  require 'core_ext/class'
20
+ require 'gosu_ext/color'
21
+ require 'gosu_ext/gosu_constants'
22
+ require 'tmx_ext/tile_set'
23
+ require 'tmx_ext/object'
19
24
 
20
25
  require 'locale/locale'
21
26
 
@@ -132,7 +137,7 @@ module Metro
132
137
  end
133
138
 
134
139
  require 'setup_handlers/move_to_game_directory'
135
- require 'setup_handlers/load_game_files'
136
140
  require 'setup_handlers/load_game_configuration'
141
+ require 'setup_handlers/load_game_files'
137
142
  require 'setup_handlers/exit_if_dry_run'
138
143
  require 'setup_handlers/reload_game_on_game_file_changes'
@@ -39,14 +39,14 @@ module Metro
39
39
  # Perform a step of an animation, if it hasn't already been completed.
40
40
  #
41
41
  def update
42
- return if completed?
42
+ return if update_completed?
43
43
 
44
44
  execute_step
45
45
  next_step
46
46
 
47
- complete! if completed?
47
+ complete! if update_completed?
48
48
  end
49
-
49
+
50
50
  #
51
51
  # @return the current step of the animation.
52
52
  #
@@ -67,12 +67,12 @@ module Metro
67
67
  def step_interval
68
68
  1
69
69
  end
70
-
71
- #
70
+
71
+ #
72
72
  # @return true if the animation has completed all the actions, false
73
73
  # if there are remaining actions.
74
- #
75
- def completed?
74
+ #
75
+ def update_completed?
76
76
  current_step >= interval
77
77
  end
78
78
 
@@ -66,6 +66,7 @@ module Metro
66
66
  @up_actions ||= {}
67
67
  @down_actions ||= {}
68
68
  @held_actions ||= {}
69
+ @mouse_movement_actions ||= []
69
70
  @custom_notifications ||= HashWithIndifferentAccess.new([])
70
71
  end
71
72
 
@@ -179,6 +180,33 @@ module Metro
179
180
  alias_method :button_hold, :on_hold
180
181
  alias_method :button_held, :on_hold
181
182
 
183
+
184
+ #
185
+ # Register for mouse movements events. These events are fired each update
186
+ # providing an event which contains the current position of the mouse.
187
+ #
188
+ # @note mouse movement events fire with each update so it is up to the
189
+ # receiving object of the event to determine if the new mouse movement
190
+ # is a delta.
191
+ #
192
+ # @note mouse movement events require that the window be specified during initialization.
193
+ #
194
+ # @example Registering for button held events
195
+ #
196
+ # class ExampleScene
197
+ #
198
+ # draws :player
199
+ #
200
+ # event :on_mouse_movement do |event|
201
+ # player.position = event.mouse_point
202
+ # end
203
+ # end
204
+ #
205
+ def on_mouse_movement(*args,&block)
206
+ options = (args.last.is_a?(Hash) ? args.pop : {})
207
+ @mouse_movement_actions << ( block || lambda { |instance| send(options[:do]) } )
208
+ end
209
+
182
210
  #
183
211
  # Register for a custom notification event. These events are fired when
184
212
  # another object within the game posts a notification with matching criteria.
@@ -217,7 +245,11 @@ module Metro
217
245
  custom_notifications[param.to_sym] = custom_notifications[param.to_sym] + [ block ]
218
246
  end
219
247
 
220
- attr_reader :up_actions, :down_actions, :held_actions, :custom_notifications
248
+ attr_reader :up_actions, :down_actions, :held_actions
249
+
250
+ attr_reader :mouse_movement_actions
251
+
252
+ attr_reader :custom_notifications
221
253
 
222
254
  def _on(hash,args,block)
223
255
  options = (args.last.is_a?(Hash) ? args.pop : {})
@@ -254,6 +286,16 @@ module Metro
254
286
  end
255
287
  end
256
288
 
289
+ #
290
+ # Fire events for all the registered actions that are suppose to receive
291
+ # the mouse movement events.
292
+ #
293
+ def fire_events_for_mouse_movement
294
+ mouse_movement_actions.each do |action|
295
+ execute_block_for_target(&action)
296
+ end
297
+ end
298
+
257
299
  def execute_block_for_target(&block)
258
300
  event_data = EventData.new(window)
259
301
  target.instance_exec(event_data,&block)
@@ -25,6 +25,13 @@ module Metro
25
25
  current_state.each {|cs| cs.fire_events_for_held_buttons }
26
26
  end
27
27
 
28
+ #
29
+ # Fire events for mouse events within the current game state
30
+ #
31
+ def fire_events_for_mouse_movement
32
+ current_state.each {|cs| cs.fire_events_for_mouse_movement }
33
+ end
34
+
28
35
  #
29
36
  # Fire events for button up for the current game state
30
37
  #
data/lib/metro/image.rb CHANGED
@@ -32,6 +32,12 @@ module Metro
32
32
  # path: "asset_path", tileable: tileable
33
33
  #
34
34
  def self.find_or_create(options)
35
+ begin
36
+ File.open(File.join("assets", options[:path]), "r")
37
+ rescue Exception
38
+ puts $! # <- make this prettier
39
+ options[:path] = "missing.png" # <- make this file installed by default into the assets folder of the game
40
+ end
35
41
  path = AssetPath.with(options[:path])
36
42
  images[path.to_s] or (images[path.to_s] = create(options))
37
43
  end
@@ -50,6 +56,13 @@ module Metro
50
56
  new gosu_image, asset_path.path, tileable
51
57
  end
52
58
 
59
+ def self.crop(window,image,bounds)
60
+ cropped_image = TexPlay.create_image(window,bounds.width,bounds.height)
61
+ cropped_image.refresh_cache
62
+ cropped_image.splice image, 0, 0, crop: [ bounds.left, bounds.top, bounds.right, bounds.bottom ]
63
+ cropped_image
64
+ end
65
+
53
66
  private
54
67
 
55
68
  def self.create_params(options)
@@ -49,13 +49,13 @@ module Metro
49
49
 
50
50
  #
51
51
  # This is called after an update. A model normally is not removed after
52
- # an update, however if the model responds true to #completed? then it
52
+ # an update, however if the model responds true to #update_completed? then it
53
53
  # will be removed.
54
54
  #
55
55
  # @note This method should be implemented in the Model sublclass if you
56
56
  # are interested in having the model be removed from the scene.
57
57
  #
58
- def completed? ; false ; end
58
+ def update_completed? ; false ; end
59
59
 
60
60
  #
61
61
  # This is called after every {#update} and when the OS wants the window to
@@ -65,6 +65,16 @@ module Metro
65
65
  #
66
66
  def draw ; end
67
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
+
68
78
  def self.model_name(model_name=nil)
69
79
  @model_name ||= to_s.underscore
70
80
  model_name ? @model_name = model_name.to_s : @model_name
@@ -40,7 +40,11 @@ module Metro
40
40
  # count of options will reset to the beginning of the list of options.
41
41
  # Values that proceed the start of of the list of options will fallback to the last option.
42
42
  #
43
+ # @param [Fixnum,Object] value is the integer position within the menu
44
+ # to select or the item in the options to select.
45
+ #
43
46
  def current_selected_index=(value)
47
+ value = index(value) unless value.is_a?(Fixnum)
44
48
  @current_selected_index = value || 0
45
49
  @current_selected_index = 0 if @current_selected_index >= count
46
50
  @current_selected_index = count - 1 if @current_selected_index <= -1
@@ -0,0 +1,105 @@
1
+ module Metro
2
+ module UI
3
+
4
+ #
5
+ # A physics sprite is a Metro model that is specially designed to draw and
6
+ # manage an image. A sprite maintains an image, location information, and
7
+ # rotation. It also has a physics body and shape to assist with being
8
+ # placed within a `Metro::UI::Space`.
9
+ #
10
+ class PhysicsSprite < Sprite
11
+
12
+ # @attribute
13
+ # The mass specified here is given to the body.
14
+ property :mass, default: 10
15
+
16
+ # @attribute
17
+ # The moment of inertia determines how the sprite will react to the forces
18
+ # applied to it.
19
+ property :moment_of_interia, default: 1000000
20
+
21
+ # @attribute
22
+ # A physics sprite has by default a collision shape that is a square.
23
+ # So this property defines the length of one side which is used to create
24
+ # the appropriately sized shape for the sprite.
25
+ property :shape_size, default: 48.0
26
+
27
+ # @attribute
28
+ # The name of the shape. This name is important when the space defines
29
+ # actions based on the collision of particular objects. By default all
30
+ # physics sprites are named 'object'.
31
+ property :shape_name, type: :text, default: "object"
32
+
33
+ # @attribute
34
+ # When this value is true the bounding box will be placed around the
35
+ # sprite. This is useful in determining correct sizes and collisions.
36
+ property :debug, type: :boolean, default: false
37
+
38
+ # @return the body of the physics sprite that is created with the mass
39
+ # and moment of interia specified in the other properties.
40
+ def body
41
+ @body ||= begin
42
+ body = CP::Body.new(mass,moment_of_interia)
43
+ body.p = CP::Vec2::ZERO
44
+ body.v = CP::Vec2::ZERO
45
+ body.a = 0
46
+ body
47
+ end
48
+ end
49
+
50
+ # @return a polygon shape for the physics sprite with the size based on
51
+ # the `shape_size` property value.
52
+ def shape
53
+ @shape ||= begin
54
+ poly_array = [ [ -1 * shape_size, -1 * shape_size ],
55
+ [ -1 * shape_size, shape_size ],
56
+ [ shape_size, shape_size ],
57
+ [ shape_size, -1 * shape_size ] ].map do |x,y|
58
+ CP::Vec2.new(x,y)
59
+ end
60
+
61
+ new_shape = CP::Shape::Poly.new(body,poly_array, CP::Vec2::ZERO)
62
+ new_shape.collision_type = shape_name.to_sym
63
+ new_shape.e = 0.0
64
+ new_shape
65
+
66
+ end
67
+ end
68
+
69
+ # An helper method that makes it easy to apply an impulse to the body at
70
+ # the center of the body. The impulse provided is in two parameters, the
71
+ # x and y component.
72
+ def push(x_amount,y_amount)
73
+ body.apply_impulse(CP::Vec2.new(x_amount,y_amount),CP::Vec2.new(0.0, 0.0))
74
+ end
75
+
76
+ # Upon the scene start the body is assigned the x and y position. If this
77
+ # method is overriden the position will need to be set manually.
78
+ def show
79
+ body.p = CP::Vec2.new(x,y)
80
+ end
81
+
82
+ # On update track the position of the sprite based on the position of the
83
+ # physics body.
84
+ def update
85
+ self.x = body.p.x
86
+ self.y = body.p.y
87
+ end
88
+
89
+ # On draw, draw the specified sprite.
90
+ def draw
91
+ angle_in_degrees = body.a.radians.to_degrees
92
+ image.draw_rot(x,y,z_order,angle_in_degrees)
93
+
94
+ draw_bounding_box if debug
95
+ end
96
+
97
+ def draw_bounding_box
98
+ @bounding_box_border ||= create "metro::ui::border"
99
+ @bounding_box_border.position = Point.at(position.x - shape_size,shape.bb.t)
100
+ @bounding_box_border.dimensions = Dimensions.of(shape.bb.r - shape.bb.l,shape.bb.b - shape.bb.t)
101
+ @bounding_box_border.draw
102
+ end
103
+ end
104
+ end
105
+ end