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 +15 -0
- data/Gemfile +2 -0
- data/README.md +18 -19
- data/changelog.md +5 -1
- data/lib/core_ext/numeric.rb +17 -0
- data/lib/metro.rb +8 -3
- data/lib/metro/animation/on_update_operation.rb +7 -7
- data/lib/metro/events/event_relay.rb +43 -1
- data/lib/metro/events/event_state_manager.rb +7 -0
- data/lib/metro/image.rb +13 -0
- data/lib/metro/models/model.rb +12 -2
- data/lib/metro/models/properties/options_property/options.rb +4 -0
- data/lib/metro/models/ui/physics_sprite.rb +105 -0
- data/lib/metro/models/ui/space.rb +152 -0
- data/lib/metro/models/ui/sprite.rb +2 -2
- data/lib/metro/models/ui/tile_map.rb +133 -0
- data/lib/metro/models/ui/tmx/isometric_position.rb +43 -0
- data/lib/metro/models/ui/tmx/orthogonal_position.rb +15 -0
- data/lib/metro/models/ui/tmx/tile_layer.rb +78 -0
- data/lib/metro/models/ui/ui.rb +3 -0
- data/lib/metro/scene.rb +2 -1
- data/lib/metro/units/rectangle_bounds.rb +75 -5
- data/lib/metro/version.rb +4 -4
- data/lib/metro/window.rb +1 -0
- data/lib/templates/game/assets/missing.png +0 -0
- data/lib/tmx_ext/object.rb +61 -0
- data/lib/tmx_ext/object_shape.rb +93 -0
- data/lib/tmx_ext/tile_set.rb +41 -0
- data/metro.gemspec +3 -1
- data/metro.png +0 -0
- data/spec/core_ext/numeric_spec.rb +28 -0
- data/spec/metro/image_spec.rb +33 -0
- data/spec/metro/units/rectangle_bounds_spec.rb +56 -0
- data/spec/tmx_ext/object_spec.rb +49 -0
- data/spec/tmx_ext/tile_set_spec.rb +24 -0
- metadata +56 -27
data/lib/metro/scene.rb
CHANGED
|
@@ -375,7 +375,7 @@ module Metro
|
|
|
375
375
|
def base_update
|
|
376
376
|
updaters.each { |updater| updater.update }
|
|
377
377
|
update
|
|
378
|
-
updaters.reject! { |updater| updater.
|
|
378
|
+
updaters.reject! { |updater| updater.update_completed? }
|
|
379
379
|
end
|
|
380
380
|
|
|
381
381
|
#
|
|
@@ -394,6 +394,7 @@ module Metro
|
|
|
394
394
|
def base_draw
|
|
395
395
|
drawers.each { |drawer| drawer.draw }
|
|
396
396
|
draw
|
|
397
|
+
drawers.reject! { |drawer| drawer.draw_completed? }
|
|
397
398
|
end
|
|
398
399
|
|
|
399
400
|
# This provides the functionality for view handling.
|
|
@@ -23,24 +23,90 @@ module Metro
|
|
|
23
23
|
@bottom = params[:bottom].to_f
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
#
|
|
27
|
+
# Move the bounds by the amount specified in the point.
|
|
28
|
+
#
|
|
29
|
+
def shift(point)
|
|
30
|
+
self.left = self.left + point.x
|
|
31
|
+
self.right = self.right + point.x
|
|
32
|
+
self.top = self.top + point.y
|
|
33
|
+
self.bottom = self.bottom + point.y
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Create a new RectangleBounds that is larger than the
|
|
38
|
+
# current bounds, given the specifed hash of parameters
|
|
39
|
+
# that contain the amount to expand in the four directions
|
|
40
|
+
# left, right, top, bottom.
|
|
41
|
+
#
|
|
42
|
+
def enlarge(params = {})
|
|
43
|
+
self.class.new(left: left - params[:left].to_i,
|
|
44
|
+
right: right + params[:right].to_i,
|
|
45
|
+
top: top - params[:top].to_i,
|
|
46
|
+
bottom: bottom + params[:bottom].to_i)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def shrink(params = {})
|
|
50
|
+
self.class.new(left: left + params[:left].to_i,
|
|
51
|
+
right: right - params[:right].to_i,
|
|
52
|
+
top: top + params[:top].to_i,
|
|
53
|
+
bottom: bottom - params[:bottom].to_i)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def clamp(point)
|
|
57
|
+
return point if contains?(point)
|
|
58
|
+
|
|
59
|
+
new_point = Point.new(point.x,point.y)
|
|
60
|
+
|
|
61
|
+
if point.x < left
|
|
62
|
+
new_point.x = left
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if point.x > right
|
|
66
|
+
new_point.x = right
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if point.y < top
|
|
70
|
+
new_point.y = top
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if point.y > bottom
|
|
74
|
+
new_point.y = bottom
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
new_point
|
|
78
|
+
end
|
|
79
|
+
|
|
26
80
|
def top_left
|
|
27
|
-
|
|
81
|
+
point_at left, top
|
|
28
82
|
end
|
|
29
83
|
|
|
30
84
|
def top_right
|
|
31
|
-
|
|
85
|
+
point_at right, top
|
|
32
86
|
end
|
|
33
87
|
|
|
34
88
|
def bottom_right
|
|
35
|
-
|
|
89
|
+
point_at right, bottom
|
|
36
90
|
end
|
|
37
91
|
|
|
38
92
|
def bottom_left
|
|
39
|
-
|
|
93
|
+
point_at left, bottom
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def width
|
|
97
|
+
(right - left)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def height
|
|
101
|
+
(bottom - top)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def center
|
|
105
|
+
top_left + point_at(width/2,height/2)
|
|
40
106
|
end
|
|
41
107
|
|
|
42
108
|
def dimensions
|
|
43
|
-
Dimensions.of
|
|
109
|
+
Dimensions.of width, height
|
|
44
110
|
end
|
|
45
111
|
|
|
46
112
|
def ==(value)
|
|
@@ -68,6 +134,10 @@ module Metro
|
|
|
68
134
|
|
|
69
135
|
private
|
|
70
136
|
|
|
137
|
+
def point_at(x,y)
|
|
138
|
+
Point.at(x,y)
|
|
139
|
+
end
|
|
140
|
+
|
|
71
141
|
def calculation_requirements
|
|
72
142
|
[ :left, :right, :top, :bottom ]
|
|
73
143
|
end
|
data/lib/metro/version.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module Metro
|
|
2
|
-
VERSION = "0.3.
|
|
2
|
+
VERSION = "0.3.5"
|
|
3
3
|
WEBSITE = "https://github.com/burtlo/metro"
|
|
4
|
-
CONTACT_EMAILS = ["
|
|
5
|
-
|
|
4
|
+
CONTACT_EMAILS = ["franklin.webber@gmail.com"]
|
|
5
|
+
|
|
6
6
|
def self.changes_for_version(version)
|
|
7
7
|
|
|
8
8
|
change = Struct::Changes.new(nil,[])
|
|
@@ -28,5 +28,5 @@ module Metro
|
|
|
28
28
|
|
|
29
29
|
change
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
end
|
data/lib/metro/window.rb
CHANGED
|
Binary file
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Tmx
|
|
2
|
+
|
|
3
|
+
class Object
|
|
4
|
+
|
|
5
|
+
# TODO: the mass and moment of interia should configurable through properties
|
|
6
|
+
def body
|
|
7
|
+
@body ||= CP::Body.new default_mass, default_moment_of_inertia
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def shape
|
|
11
|
+
@poly_shape ||= begin
|
|
12
|
+
new_shape = CP::Shape::Poly.new(body,poly_vec2s,default_shape_attach_point)
|
|
13
|
+
new_shape.collision_type = type.to_sym
|
|
14
|
+
new_shape.e = default_elasticity
|
|
15
|
+
new_shape.sensor = default_sensor
|
|
16
|
+
new_shape
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# A TMX object currently has an array of points in a format
|
|
24
|
+
# list of strings. This will convert the points into
|
|
25
|
+
# list of CP::Vec2 objects which can be used to create the
|
|
26
|
+
# proper CP::Shape::Poly for the Object.
|
|
27
|
+
#
|
|
28
|
+
# @note this assumes that we want to convert the points into
|
|
29
|
+
# a format of vec2s specifically for a CP::Shape::Poly
|
|
30
|
+
# shape.
|
|
31
|
+
#
|
|
32
|
+
def poly_vec2s
|
|
33
|
+
points.map do |point|
|
|
34
|
+
x,y = point.split(",").map {|p| p.to_i }
|
|
35
|
+
CP::Vec2.new(x,y)
|
|
36
|
+
end.reverse
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def default_sensor
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def default_mass
|
|
44
|
+
Float::INFINITY
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def default_moment_of_inertia
|
|
48
|
+
Float::INFINITY
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def default_elasticity
|
|
52
|
+
0.0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def default_shape_attach_point
|
|
56
|
+
CP::Vec2::ZERO
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Tmx
|
|
2
|
+
module ObjectShape
|
|
3
|
+
extend self
|
|
4
|
+
|
|
5
|
+
module ShapeDefaults
|
|
6
|
+
def default_sensor
|
|
7
|
+
false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def default_elasticity
|
|
11
|
+
0.0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def default_shape_attach_point
|
|
15
|
+
CP::Vec2::ZERO
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class PolyShape
|
|
20
|
+
include ShapeDefaults
|
|
21
|
+
|
|
22
|
+
def match?(object)
|
|
23
|
+
object.contents['shape'] == 'polygon'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def shape(object)
|
|
27
|
+
new_shape = CP::Shape::Poly.new(object.body,poly_vec2s(object),default_shape_attach_point)
|
|
28
|
+
new_shape.collision_type = object.type.to_sym
|
|
29
|
+
new_shape.e = default_elasticity
|
|
30
|
+
new_shape.sensor = default_sensor
|
|
31
|
+
new_shape
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
# A TMX object currently has an array of points in a format
|
|
36
|
+
# list of strings. This will convert the points into
|
|
37
|
+
# list of CP::Vec2 objects which can be used to create the
|
|
38
|
+
# proper CP::Shape::Poly for the Object.
|
|
39
|
+
#
|
|
40
|
+
# @note this assumes that we want to convert the points into
|
|
41
|
+
# a format of vec2s specifically for a CP::Shape::Poly
|
|
42
|
+
# shape.
|
|
43
|
+
#
|
|
44
|
+
def poly_vec2s(object)
|
|
45
|
+
object.points.map do |point|
|
|
46
|
+
x,y = point.split(",").map {|p| p.to_i }
|
|
47
|
+
CP::Vec2.new(x,y)
|
|
48
|
+
end.reverse
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class CircularShape
|
|
54
|
+
include ShapeDefaults
|
|
55
|
+
|
|
56
|
+
def match?(object)
|
|
57
|
+
object.contents['shape'] == 'ellipse'
|
|
58
|
+
# raise "Only circular shapes are allowed to be specified" if (object.width / 2) != (object.height / 2)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def shape(object)
|
|
62
|
+
radius = object.width / 2
|
|
63
|
+
offset = CP::Vec2.new(0,0)
|
|
64
|
+
new_shape = CP::Shape::Circle.new(object.body, radius, offset)
|
|
65
|
+
new_shape.collision_type = object.type.to_sym
|
|
66
|
+
new_shape.e = default_elasticity
|
|
67
|
+
new_shape.sensor = default_sensor
|
|
68
|
+
new_shape
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class UnknownShape
|
|
74
|
+
def match?(object)
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def shape(object)
|
|
79
|
+
raise "Invalid Shape defined in Object: #{object}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def shapes
|
|
84
|
+
[ PolyShape.new, CircularShape.new, UnknownShape.new ]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def create_from_tmx_object(object)
|
|
88
|
+
shapes.find { |shape| shape.match?(object) }.shape(object)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Tmx
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Define additional functionaly or override existing functionaliy on
|
|
5
|
+
# the Tmx class to make it compatible with Metro.
|
|
6
|
+
#
|
|
7
|
+
class TileSet
|
|
8
|
+
attr_accessor :window
|
|
9
|
+
|
|
10
|
+
def images
|
|
11
|
+
@images ||= raw_image_tiles.map {|image| crop_image(image) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def raw_image_tiles
|
|
17
|
+
Gosu::Image.load_tiles(window, image_path, full_image_width, full_image_height, false)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def crop_image(image)
|
|
21
|
+
Metro::Image.crop window, image, crop_bounds
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def full_image_width
|
|
25
|
+
tilewidth + spacing
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def full_image_height
|
|
29
|
+
tileheight + spacing
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def crop_bounds
|
|
33
|
+
@crop_bounds ||= Metro::Units::RectangleBounds.new left: margin, top: margin,
|
|
34
|
+
right: full_image_width, bottom: full_image_height
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def image_path
|
|
38
|
+
Metro::AssetPath.with(image).filepath
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/metro.gemspec
CHANGED
|
@@ -25,9 +25,11 @@ Gem::Specification.new do |gem|
|
|
|
25
25
|
gem.homepage = Metro::WEBSITE
|
|
26
26
|
|
|
27
27
|
gem.add_dependency 'gosu', '~> 0.7'
|
|
28
|
+
gem.add_dependency 'texplay', '~> 0.4'
|
|
29
|
+
gem.add_dependency 'tmx', '~> 0.1.2'
|
|
28
30
|
gem.add_dependency 'thor', '~> 0.16.0'
|
|
29
31
|
gem.add_dependency 'i18n', '~> 0.6.1'
|
|
30
|
-
gem.add_dependency '
|
|
32
|
+
gem.add_dependency 'activesupport', '~> 3.0.0'
|
|
31
33
|
gem.add_dependency 'listen', '~> 0.6.0'
|
|
32
34
|
gem.add_development_dependency 'rspec', '~> 2.11'
|
|
33
35
|
|
data/metro.png
ADDED
|
Binary file
|
|
@@ -75,4 +75,32 @@ describe Numeric do
|
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
describe "#to_degrees" do
|
|
79
|
+
context "when using a Float" do
|
|
80
|
+
it "converts the radians to degrees" do
|
|
81
|
+
3.1415.radians.to_degrees.should eq 179.99469134034814
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "when using an Integer" do
|
|
86
|
+
it "converts the radians to degrees" do
|
|
87
|
+
4.radians.to_degrees.should eq 229.1831180523293
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "#to_radians" do
|
|
93
|
+
context "when using a Float" do
|
|
94
|
+
it "converts the degrees to radians" do
|
|
95
|
+
360.5.degrees.to_radians.should eq 6.291911953439557
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
context "when using an Integer" do
|
|
100
|
+
it "converts the degrees to radians" do
|
|
101
|
+
180.degrees.to_radians.should eq 3.141592653589793
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
78
106
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Metro::Image do
|
|
4
|
+
|
|
5
|
+
describe "Class Methods" do
|
|
6
|
+
|
|
7
|
+
let(:subject) { described_class }
|
|
8
|
+
|
|
9
|
+
describe ".crop" do
|
|
10
|
+
|
|
11
|
+
let(:image) { stub('Original Image') }
|
|
12
|
+
let(:window) { stub('Gosu::Window') }
|
|
13
|
+
let(:mock_image) { mock("TexPlay Created Image",refresh_cache: nil) }
|
|
14
|
+
let(:bounds) { Metro::Units::RectangleBounds.new(left: 2,top: 2,right: 30,bottom:30) }
|
|
15
|
+
|
|
16
|
+
let(:expected_crop_params) { [ bounds.left, bounds.top, bounds.right, bounds.bottom ]}
|
|
17
|
+
|
|
18
|
+
it "crops the image with the bounds provided" do
|
|
19
|
+
TexPlay.should_receive(:create_image).and_return(mock_image)
|
|
20
|
+
mock_image.should_receive(:splice).with(image,0,0,crop: expected_crop_params)
|
|
21
|
+
|
|
22
|
+
subject.crop(window,image,bounds)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "refreshes the cache for the image so when Metro reloads the images are not corrupt" do
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe RectangleBounds do
|
|
4
|
+
|
|
5
|
+
let(:subject) { described_class.new left: 20, top: 30, right: 40, bottom: 60 }
|
|
6
|
+
|
|
7
|
+
shared_examples "valid point" do
|
|
8
|
+
it "correct point" do
|
|
9
|
+
expect(given_point).to eq expected_point
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "#top_left" do
|
|
14
|
+
it_behaves_like "valid point" do
|
|
15
|
+
let(:given_point) { subject.top_left }
|
|
16
|
+
let(:expected_point) { Point.at 20, 30 }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#top_right" do
|
|
21
|
+
it_behaves_like "valid point" do
|
|
22
|
+
let(:given_point) { subject.top_right }
|
|
23
|
+
let(:expected_point) { Point.at 40, 30 }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "#bottom_left" do
|
|
28
|
+
it_behaves_like "valid point" do
|
|
29
|
+
let(:given_point) { subject.bottom_left }
|
|
30
|
+
let(:expected_point) { Point.at 20, 60 }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "#bottom_right" do
|
|
35
|
+
it_behaves_like "valid point" do
|
|
36
|
+
let(:given_point) { subject.bottom_right }
|
|
37
|
+
let(:expected_point) { Point.at 40, 60 }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "#center" do
|
|
42
|
+
it_behaves_like "valid point" do
|
|
43
|
+
let(:given_point) { subject.center }
|
|
44
|
+
let(:expected_point) { Point.at 30, 45 }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
describe "#dimensions" do
|
|
50
|
+
it "correct dimensions" do
|
|
51
|
+
expect(subject.dimensions).to eq Dimensions.of(20,30)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
end
|