metro 0.3.4 → 0.3.5

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