metro 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +51 -20
- data/changelog.md +9 -0
- data/lib/metro/events/hit_list.rb +7 -8
- data/lib/metro/font.rb +3 -0
- data/lib/metro/game.rb +7 -3
- data/lib/metro/models/model.rb +16 -13
- data/lib/metro/models/properties/animation_property.rb +5 -1
- data/lib/metro/models/properties/dimensions_property.rb +8 -7
- data/lib/metro/models/properties/font_property.rb +2 -1
- data/lib/metro/models/properties/model_property.rb +84 -0
- data/lib/metro/models/properties/property.rb +2 -1
- data/lib/metro/models/ui/border.rb +69 -0
- data/lib/metro/models/ui/fps.rb +54 -0
- data/lib/metro/models/ui/generic.rb +8 -1
- data/lib/metro/models/ui/grid_drawer.rb +17 -5
- data/lib/metro/models/ui/image.rb +40 -8
- data/lib/metro/models/ui/label.rb +48 -7
- data/lib/metro/models/ui/menu.rb +61 -8
- 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 +6 -0
- data/lib/metro/scene.rb +1 -1
- data/lib/metro/transitions/edit_transition_scene.rb +28 -1
- data/lib/metro/units/dimensions.rb +29 -2
- data/lib/metro/units/point.rb +16 -4
- data/lib/metro/units/rectangle_bounds.rb +38 -16
- data/lib/metro/version.rb +1 -1
- data/lib/setup_handlers/reload_game_on_game_file_changes.rb +6 -1
- data/lib/templates/game/scenes/first_scene.rb +4 -0
- metadata +14 -8
data/README.md
CHANGED
@@ -7,7 +7,10 @@
|
|
7
7
|
|
8
8
|
```
|
9
9
|
|
10
|
-
Metro is a framework built around [gosu](https://github.com/jlnr/gosu) (the 2D
|
10
|
+
Metro is a framework built around [gosu](https://github.com/jlnr/gosu) (the 2D
|
11
|
+
game development library in Ruby). The goal of Metro is to enforce common
|
12
|
+
conceptual structures and conventions making it easier to quickly generate a
|
13
|
+
game.
|
11
14
|
|
12
15
|
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/burtlo/metro)
|
13
16
|
|
@@ -21,42 +24,62 @@ You want to develop games in Ruby.
|
|
21
24
|
|
22
25
|
### Why not just use Gosu?
|
23
26
|
|
24
|
-
Gosu does a lot of great work bringing OpenGL to Ruby. However, when you finish
|
27
|
+
Gosu does a lot of great work bringing OpenGL to Ruby. However, when you finish
|
28
|
+
the [initial tutorial](https://github.com/jlnr/gosu/wiki/Ruby-Tutorial) you are
|
29
|
+
left with a brittle game that is very resistant to changes or new features.
|
25
30
|
|
26
|
-
* Metro provides the concept of a
|
31
|
+
* Metro provides the concept of a
|
32
|
+
[Scene](https://github.com/burtlo/metro/wiki/Scenes) which is the first
|
33
|
+
abstraction you would likely build after completing the tutorial.
|
27
34
|
|
28
|
-
> Developing your game in individual scenes will make it easier to logically
|
35
|
+
> Developing your game in individual scenes will make it easier to logically
|
36
|
+
layout your game.
|
29
37
|
|
30
|
-
* Sane management of images, animations, fonts, songs, and samples through
|
38
|
+
* Sane management of images, animations, fonts, songs, and samples through
|
39
|
+
[model properties](https://github.com/burtlo/metro/wiki/Model-properties).
|
31
40
|
|
32
|
-
> Having to load and cache fonts and images in every one of your models is
|
41
|
+
> Having to load and cache fonts and images in every one of your models is
|
42
|
+
tedious. It is also is wasteful as several of the same fonts are being used all
|
43
|
+
over the place.
|
33
44
|
|
34
45
|
* [Key-frame animations](https://github.com/burtlo/metro/wiki/Animations)
|
35
46
|
|
36
|
-
> Metro makes it simple to move an actor from one position to another position.
|
47
|
+
> Metro makes it simple to move an actor from one position to another position.
|
48
|
+
So simple movements, fades, color changes, and really any property change over
|
49
|
+
time is defined very simply.
|
37
50
|
|
38
51
|
* [Event Handling](https://github.com/burtlo/metro/wiki/Events)
|
39
52
|
|
40
|
-
> Delete those huge `if ... elsif ... else` input checking structures for
|
53
|
+
> Delete those huge `if ... elsif ... else` input checking structures for
|
54
|
+
keyboard, gamepad, and mouse button presses (down,up, and held). Metro makes it
|
55
|
+
easy to define them and an attach a course of action to take when the event
|
56
|
+
happens.
|
41
57
|
|
42
58
|
### Why not use Chingu or Gamebox?
|
43
59
|
|
44
60
|
Both [Gamebox](https://github.com/shawn42/gamebox) and
|
45
|
-
[Chingu](https://github.com/ippa/chingu) are
|
46
|
-
larger set of features.
|
61
|
+
[Chingu](https://github.com/ippa/chingu) are more mature libraries with a
|
62
|
+
larger set of features. I encourage you to check out those libraries.
|
47
63
|
|
48
|
-
|
49
|
-
|
64
|
+
Metro's primary goal is to be a framework of features that make game development
|
65
|
+
joyful.
|
50
66
|
|
51
67
|
* Active Reloading while building your scenes.
|
52
68
|
|
53
69
|
> Adjustments to your game code while working on a scene will automatically
|
54
|
-
reload your game code. The template game sets up a shortcut key (**Ctrl+R**)
|
70
|
+
reload your game code. The template game sets up a shortcut key (**Ctrl+R**)
|
71
|
+
that allows you to explicitly reload the game and the current scene.
|
55
72
|
|
56
73
|
* Scene Edit Support
|
57
74
|
|
58
|
-
>
|
59
|
-
|
75
|
+
> Scenes can enter an edit mode which allows you to re-position actors within
|
76
|
+
the scene. The changes can then be saved back to the view. This allows you to
|
77
|
+
fine tune the layout of those scene elements, making it easier to get things
|
78
|
+
pixel perfect.
|
79
|
+
|
80
|
+
Metro's secondary goal is to make it easier for individuals familiar with Rails
|
81
|
+
get into game development. That is the reason for some of the design choices,
|
82
|
+
the opinionated structure, and generators that come with Metro.
|
60
83
|
|
61
84
|
### Why you shouldn't use Metro?
|
62
85
|
|
@@ -64,11 +87,16 @@ Metro has some the following limitations:
|
|
64
87
|
|
65
88
|
* Limited to the gems defined within Metro
|
66
89
|
|
67
|
-
> At this point in time you are not able to define and package additional
|
90
|
+
> At this point in time you are not able to define and package additional
|
91
|
+
dependencies with your game. This means if you are using a gem that is not
|
92
|
+
already defined by Metro you will run into trouble when running it on alternate
|
93
|
+
systems. This will likely be addressed in the future when more demand arises.
|
68
94
|
|
69
95
|
* Difficult Deployment
|
70
96
|
|
71
|
-
> For individuals to play your game, they will also have to install Metro.
|
97
|
+
> For individuals to play your game, they will also have to install Metro.
|
98
|
+
However, work is being made to bring some simple packaging to Metro games to
|
99
|
+
make them stand-along executables.
|
72
100
|
|
73
101
|
## Installation
|
74
102
|
|
@@ -80,7 +108,8 @@ $ gem install metro
|
|
80
108
|
|
81
109
|
### Running a Game
|
82
110
|
|
83
|
-
By default `metro` will look for a file named 'metro' within the current working
|
111
|
+
By default `metro` will look for a file named 'metro' within the current working
|
112
|
+
directory if no *gamefilename* has been provided.
|
84
113
|
|
85
114
|
```bash
|
86
115
|
$ metro GAMEFILENAME
|
@@ -104,9 +133,11 @@ Creating a Game can be done with a single command.
|
|
104
133
|
$ metro new GAMENAME
|
105
134
|
```
|
106
135
|
|
107
|
-
This should generate for you a starting game with a branding scene and a title
|
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.
|
108
138
|
|
109
|
-
The game is missing the `first` scene of the game. This can be created with the
|
139
|
+
The game is missing the `first` scene of the game. This can be created with the
|
140
|
+
scene generator:
|
110
141
|
|
111
142
|
```bash
|
112
143
|
$ metro generate scene first
|
data/changelog.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Metro
|
2
2
|
|
3
|
+
## 0.3.3 / 2012-11-28
|
4
|
+
|
5
|
+
* Edit Mode - actors within a scene can have their position edited
|
6
|
+
and saved. Actors within the scene that have a valid bounds
|
7
|
+
specified will appear within the scene with name and bounding box.
|
8
|
+
* Dimensions can now be defined as strings
|
9
|
+
* Game bounds and Game dimensions return objects of that type
|
10
|
+
* `metr::ui::fps` added and has some shortcut placements settings
|
11
|
+
|
3
12
|
## 0.3.2 / 2012-11-26
|
4
13
|
|
5
14
|
* Debug Mode will now automatically reload the game and scene on source
|
@@ -27,24 +27,22 @@ module Metro
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def update(event)
|
30
|
-
|
31
|
-
|
32
|
-
list.each { |d| d.offset(offset_x,offset_y) }
|
30
|
+
offset = offset_from_last_event(event)
|
31
|
+
list.each { |d| d.position = d.position + offset }
|
33
32
|
|
34
33
|
save_event event
|
35
34
|
end
|
36
35
|
|
37
36
|
def release(event)
|
38
|
-
|
39
|
-
|
40
|
-
list.each { |d| d.offset(offset_x,offset_y) }
|
37
|
+
offset = offset_from_last_event(event)
|
38
|
+
list.each { |d| d.position = d.position + offset }
|
41
39
|
|
42
40
|
save_event event
|
43
41
|
clear
|
44
42
|
end
|
45
43
|
|
46
44
|
def drawers_at(x,y)
|
47
|
-
hit_drawers = drawers.find_all { |drawer| drawer.contains?(x,y) }
|
45
|
+
hit_drawers = drawers.find_all { |drawer| drawer.bounds.contains?(x,y) }
|
48
46
|
|
49
47
|
# assumed that we only want one item
|
50
48
|
top_drawer = hit_drawers.inject(hit_drawers.first) {|top,drawer| drawer.z_order > top.z_order ? drawer : top }
|
@@ -52,7 +50,8 @@ module Metro
|
|
52
50
|
end
|
53
51
|
|
54
52
|
def offset_from_last_event(event)
|
55
|
-
|
53
|
+
return Point.zero unless @last_event
|
54
|
+
Metro::Units::Point.at (event.mouse_x - @last_event.mouse_x).to_i, (event.mouse_y - @last_event.mouse_y).to_i
|
56
55
|
end
|
57
56
|
|
58
57
|
def save_event(event)
|
data/lib/metro/font.rb
CHANGED
@@ -10,6 +10,9 @@ module Metro
|
|
10
10
|
super(gosu_font)
|
11
11
|
end
|
12
12
|
|
13
|
+
# An alias to Gosu::Font's height method
|
14
|
+
def size ; height ; end
|
15
|
+
|
13
16
|
#
|
14
17
|
# Return a font that matches the specified criteria. Using the name, size,
|
15
18
|
# and window a font will be generated or retrieved from the cache.
|
data/lib/metro/game.rb
CHANGED
@@ -32,10 +32,10 @@ module Metro
|
|
32
32
|
attr_reader :window
|
33
33
|
|
34
34
|
#
|
35
|
-
# @return [Scene,NilClass] the current scene that is being displayed. If
|
35
|
+
# @return [Scene,NilClass] the current scene that is being displayed. If
|
36
36
|
# this is called before the window is being displayed when this will return
|
37
37
|
# a nil value.
|
38
|
-
#
|
38
|
+
#
|
39
39
|
def current_scene
|
40
40
|
window ? window.scene : nil
|
41
41
|
end
|
@@ -52,8 +52,12 @@ module Metro
|
|
52
52
|
fetch(:height,480)
|
53
53
|
end
|
54
54
|
|
55
|
+
def bounds
|
56
|
+
Units::RectangleBounds.new left: 0, right: width, top: 0, bottom: height
|
57
|
+
end
|
58
|
+
|
55
59
|
def dimensions
|
56
|
-
|
60
|
+
Units::Dimensions.of width, height
|
57
61
|
end
|
58
62
|
|
59
63
|
def center
|
data/lib/metro/models/model.rb
CHANGED
@@ -76,6 +76,12 @@ module Metro
|
|
76
76
|
#
|
77
77
|
property :name, type: :text
|
78
78
|
|
79
|
+
#
|
80
|
+
# @return [TrueClass,FalseClass] true if the model should be saved to the
|
81
|
+
# view file, false when the model should not be savedable to the view file.
|
82
|
+
#
|
83
|
+
property :saveable_to_view, type: :boolean, default: true
|
84
|
+
|
79
85
|
#
|
80
86
|
# The window that this model that this window is currently being
|
81
87
|
# displayed.
|
@@ -130,19 +136,12 @@ module Metro
|
|
130
136
|
mc
|
131
137
|
end
|
132
138
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
false
|
140
|
-
end
|
141
|
-
|
142
|
-
# Belongs to positionable items only
|
143
|
-
def offset(x,y)
|
144
|
-
self.x += x
|
145
|
-
self.y += y
|
139
|
+
#
|
140
|
+
# By default a model has no bounds. Each subclass of model will have to
|
141
|
+
# define how their bounds are defined.
|
142
|
+
#
|
143
|
+
def bounds
|
144
|
+
Bounds.none
|
146
145
|
end
|
147
146
|
|
148
147
|
#
|
@@ -241,4 +240,8 @@ require_relative 'ui/menu'
|
|
241
240
|
require_relative 'ui/image'
|
242
241
|
require_relative 'ui/rectangle'
|
243
242
|
require_relative 'ui/grid_drawer'
|
243
|
+
require_relative 'ui/border'
|
244
|
+
require_relative 'ui/model_label'
|
245
|
+
require_relative 'ui/model_labeler'
|
246
|
+
require_relative 'ui/fps'
|
244
247
|
require_relative 'audio/song'
|
@@ -94,7 +94,11 @@ module Metro
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def default_dimensions
|
97
|
-
options[:dimensions]
|
97
|
+
if options[:dimensions]
|
98
|
+
Dimensions.parse options[:dimensions]
|
99
|
+
else
|
100
|
+
Dimensions.of 16.0, 16.0
|
101
|
+
end
|
98
102
|
end
|
99
103
|
|
100
104
|
def default_time_per_image
|
@@ -68,15 +68,16 @@ module Metro
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def default_dimensions
|
71
|
-
|
72
|
-
model.instance_eval(&block)
|
73
|
-
elsif options[:default] and options[:default].is_a? Dimensions
|
74
|
-
options[:default]
|
75
|
-
else
|
76
|
-
Dimensions.none
|
77
|
-
end
|
71
|
+
Dimensions.parse default_dimensions_params.to_s
|
78
72
|
end
|
79
73
|
|
74
|
+
private
|
75
|
+
|
76
|
+
def default_dimensions_params
|
77
|
+
block ? model.instance_eval(&block) : options[:default]
|
78
|
+
end
|
79
|
+
|
80
|
+
|
80
81
|
end
|
81
82
|
|
82
83
|
end
|
@@ -34,6 +34,7 @@ module Metro
|
|
34
34
|
# @example Using the `font_size` and `font_name` properties
|
35
35
|
#
|
36
36
|
# class Hero < Metro::Model
|
37
|
+
# property :font, default: { name: 'Comic Sans', size: 80 }
|
37
38
|
# property :color, default: "rgba(255,0,0,1.0)"
|
38
39
|
#
|
39
40
|
# def dignified
|
@@ -45,7 +46,7 @@ module Metro
|
|
45
46
|
# @example Using a font property with a different property name
|
46
47
|
#
|
47
48
|
# class Hero < Metro::Model
|
48
|
-
# property :alt_font, type: :font, default:
|
49
|
+
# property :alt_font, type: :font, default: { name: 'Helvetica', size: 80 }
|
49
50
|
#
|
50
51
|
# def draw
|
51
52
|
# puts "Font: #{alt_font_name}:#{alt_font_size}"
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Metro
|
2
|
+
class Model
|
3
|
+
|
4
|
+
#
|
5
|
+
# A model property maintains a reference to another model. This property
|
6
|
+
# allows for an existing model to be more easily composed with other models.
|
7
|
+
#
|
8
|
+
# The model is stored as a hash which describes the model.
|
9
|
+
#
|
10
|
+
# @example Defining a model property with a block
|
11
|
+
#
|
12
|
+
# class ScoreBoard < Metro::Model
|
13
|
+
# property :position
|
14
|
+
# property :score
|
15
|
+
# property :label, type: :model do
|
16
|
+
# create "metro::ui::label", text: "", position: position
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @example Defining a model property with a hash
|
21
|
+
#
|
22
|
+
# class ScoreBoard < Metro::Model
|
23
|
+
# property :position
|
24
|
+
# property :score
|
25
|
+
# property :label, type: :model, default: { model: "metro::ui::label",
|
26
|
+
# text: "", position: position }
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
class ModelProperty < Property
|
31
|
+
|
32
|
+
# When retrieving a model and the type is unsupported generate the
|
33
|
+
# model instance from the default.
|
34
|
+
get do
|
35
|
+
default_model
|
36
|
+
end
|
37
|
+
|
38
|
+
# When retrieving a hash representation of the model, convert it into
|
39
|
+
# a Metro::Model instance.
|
40
|
+
get Hash do |params|
|
41
|
+
create_model params
|
42
|
+
end
|
43
|
+
|
44
|
+
# When setting the property with an unsupported type, simply save an
|
45
|
+
# empty hash. Which later, if retrieved, it will generate a generic
|
46
|
+
# model.
|
47
|
+
set do
|
48
|
+
{}
|
49
|
+
end
|
50
|
+
|
51
|
+
# When setting the property with a hash, assume that the hash is a
|
52
|
+
# valid description of a Metro::Model.
|
53
|
+
set Hash, HashWithIndifferentAccess do |hash|
|
54
|
+
hash
|
55
|
+
end
|
56
|
+
|
57
|
+
# When setting the property with a Metro::Model, convert the model into
|
58
|
+
# a hash.
|
59
|
+
set Metro::Model do |model|
|
60
|
+
model.to_hash
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Allow for a model property to be defined with a block initialization or
|
65
|
+
# a default hash.
|
66
|
+
#
|
67
|
+
def default_model
|
68
|
+
if block
|
69
|
+
model.instance_eval(&block)
|
70
|
+
else
|
71
|
+
create_model options[:default]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Metro::Model] return a model created by the current model that
|
76
|
+
# owns the property.
|
77
|
+
def create_model
|
78
|
+
model.create params[:model], params.except(:model)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -217,4 +217,5 @@ require_relative 'position_property'
|
|
217
217
|
require_relative 'scale_property'
|
218
218
|
require_relative 'song_property'
|
219
219
|
require_relative 'sample_property'
|
220
|
-
require_relative 'options_property/options_property'
|
220
|
+
require_relative 'options_property/options_property'
|
221
|
+
require_relative 'model_property'
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Metro
|
2
|
+
module UI
|
3
|
+
|
4
|
+
#
|
5
|
+
# Draws a rectanglar border around the specififed position and dimensions
|
6
|
+
# with the width provided. This is an unfilled rectangle.
|
7
|
+
#
|
8
|
+
class Border < Metro::Model
|
9
|
+
|
10
|
+
# @attribute
|
11
|
+
# The starting position of the border.
|
12
|
+
property :position
|
13
|
+
|
14
|
+
# @attribute
|
15
|
+
# The dimension of the border.
|
16
|
+
property :dimensions
|
17
|
+
|
18
|
+
# @attribute
|
19
|
+
# The color which to use to draw the border.
|
20
|
+
property :color, default: "rgba(255,255,255,1.0)"
|
21
|
+
|
22
|
+
# @attribute
|
23
|
+
# The width of the border lines
|
24
|
+
property :border, default: 2
|
25
|
+
|
26
|
+
def draw
|
27
|
+
draw_border
|
28
|
+
end
|
29
|
+
|
30
|
+
def draw_border
|
31
|
+
draw_top
|
32
|
+
draw_bottom
|
33
|
+
draw_left
|
34
|
+
draw_right
|
35
|
+
end
|
36
|
+
|
37
|
+
def draw_top
|
38
|
+
window.draw_quad(x + border,y,color,
|
39
|
+
width + x,y,color,
|
40
|
+
x + width,y + border,color,
|
41
|
+
x + border,y + border,color,z_order)
|
42
|
+
end
|
43
|
+
|
44
|
+
def draw_left
|
45
|
+
window.draw_quad(x,y,color,
|
46
|
+
border + x,y,color,
|
47
|
+
x + border,y + border + height,color,
|
48
|
+
x,y + border + height,color,z_order)
|
49
|
+
end
|
50
|
+
|
51
|
+
def draw_right
|
52
|
+
window.draw_quad(x + width,y,color,
|
53
|
+
x + width + border,y,color,
|
54
|
+
x + width + border,y + border + height,color,
|
55
|
+
x + width,y + border + height,color,z_order)
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def draw_bottom
|
60
|
+
window.draw_quad(x + border,y + height,color,
|
61
|
+
width + x,y + height,color,
|
62
|
+
x + width,y + border + height,color,
|
63
|
+
x + border,y + border + height,color,z_order)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|