tmx 0.1.0 → 0.1.1
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 +8 -8
- data/README.md +1 -1
- data/Rakefile +1 -0
- data/lib/tmx/image_layer.rb +5 -0
- data/lib/tmx/map.rb +11 -0
- data/lib/tmx/object.rb +5 -0
- data/lib/tmx/object_group.rb +9 -0
- data/lib/tmx/parsers/json.rb +49 -1
- data/lib/tmx/parsers/tmx.rb +59 -1
- data/lib/tmx/version.rb +1 -1
- data/spec/features/json_format_spec.rb +119 -11
- data/spec/features/json_isometric_format_spec.rb +76 -0
- data/spec/features/xml_format_spec.rb +128 -21
- data/spec/fixtures/map-isometric.json +50 -0
- data/spec/fixtures/map.json +153 -11
- data/spec/fixtures/map_csv.tmx +36 -18
- data/spec/fixtures/map_gzip.tmx +35 -6
- data/spec/fixtures/map_uncompressed.tmx +35 -6
- data/spec/fixtures/map_xml.tmx +35 -197
- data/spec/fixtures/map_zlib.tmx +31 -5
- data/spec/fixtures/tiles.png +0 -0
- data/tmx.gemspec +1 -1
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OTA3ZjIyZjNjZGZhYTg0ZGVjNWY0NjkyZDQ2MjcwYTM2YmRkZmY3NA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ODA2YWY5OTJjN2FiMzFlOTYyN2M3YWIwODgxY2Q5ODc4MjQ2ZDRlNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MjBlM2NhZTU3OTZjYzZkZjcyMjU4ZmVhNjIyNDE1ZjFlMjY1OTgwMzIwMzFk
|
10
|
+
Y2NjYTE1Mjg4NGMzNjZiYzc5OTc5M2M0M2Y5ZDM1NGRhYWRiNzg3ODQ3ZjQ0
|
11
|
+
YTc0NmQzNjU5NDU4ZDI5NTNlYTkwZTViZjMzOTFhNTQ2ZGM4ZjY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODIyZGIzNmJkOTI2NzExZTc0YzA3YmJjMzdiNzY3YjA5NzM2NTExMTliMzIw
|
14
|
+
NGRmN2M0ZDgyMTg4Yzk0YTc4ZGMxY2Q5OWY3MTMwOThiNDkyOTIwOThhYTlm
|
15
|
+
OTQ1MzQ2ZWRlNzE3MmQyYzkyM2RmOTI3NDRmNzk3YTlmYjAzMDI=
|
data/README.md
CHANGED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/tmx/map.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'tmx/tile_set'
|
2
2
|
require 'tmx/layer'
|
3
|
+
require 'tmx/object_group'
|
4
|
+
require 'tmx/object'
|
5
|
+
require 'tmx/image_layer'
|
3
6
|
|
4
7
|
module Tmx
|
5
8
|
|
@@ -11,5 +14,13 @@ module Tmx
|
|
11
14
|
def tilesets
|
12
15
|
@tilesets ||= Array(contents['tilesets']).map {|set| TileSet.new set.merge(contents: set) }
|
13
16
|
end
|
17
|
+
|
18
|
+
def object_groups
|
19
|
+
@object_groups ||= Array(contents['object_groups']).map {|group| ObjectGroup.new group.merge(contents: group) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def image_layers
|
23
|
+
@object_groups ||= Array(contents['image_layers']).map {|layer| ImageLayer.new layer.merge(contents: layer) }
|
24
|
+
end
|
14
25
|
end
|
15
26
|
end
|
data/lib/tmx/object.rb
ADDED
data/lib/tmx/parsers/json.rb
CHANGED
@@ -14,8 +14,56 @@ module Tmx
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def parse(contents)
|
17
|
-
Oj.load(contents)
|
17
|
+
parsed_contents = Oj.load(contents)
|
18
|
+
|
19
|
+
object_layers = parsed_contents["layers"].find_all do |layer|
|
20
|
+
layer["type"] == "objectgroup"
|
21
|
+
end
|
22
|
+
|
23
|
+
parsed_contents["object_groups"] = object_layers
|
24
|
+
|
25
|
+
object_layers.each do |object_layer|
|
26
|
+
parse_object_layer(object_layer)
|
27
|
+
end
|
28
|
+
|
29
|
+
image_layers = parsed_contents["layers"].find_all do |layer|
|
30
|
+
layer["type"] == "imagelayer"
|
31
|
+
end
|
32
|
+
|
33
|
+
parsed_contents["image_layers"] = image_layers
|
34
|
+
|
35
|
+
parsed_contents["layers"].reject! {|layer| layer["type"] != "tilelayer" }
|
36
|
+
|
37
|
+
parsed_contents
|
38
|
+
|
18
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def parse_object_layer(object_layer)
|
44
|
+
object_layer["objects"].each do |object|
|
45
|
+
|
46
|
+
if object["ellipse"]
|
47
|
+
object["shape"] = "ellipse"
|
48
|
+
elsif object["polyline"]
|
49
|
+
object["shape"] = "polyline"
|
50
|
+
object["points"] = object["polyline"].map {|h| "#{h["x"]},#{h["y"]}" }
|
51
|
+
elsif object["polygon"]
|
52
|
+
object["shape"] = "polygon"
|
53
|
+
object["points"] = object["polygon"].map {|h| "#{h["x"]},#{h["y"]}" }
|
54
|
+
else
|
55
|
+
x = object["x"]
|
56
|
+
y = object["y"]
|
57
|
+
width = object["width"]
|
58
|
+
height = object["height"]
|
59
|
+
|
60
|
+
object["shape"] = "polygon"
|
61
|
+
object["points"] = [ "#{x},#{y}", "#{x + width},#{y}", "#{x + width},#{y + height}", "#{x},#{y + height}" ]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
19
67
|
end
|
20
68
|
|
21
69
|
end
|
data/lib/tmx/parsers/tmx.rb
CHANGED
@@ -32,7 +32,9 @@ module Tmx
|
|
32
32
|
"tileheight" => map_attr(xml,"tileheight").to_i,
|
33
33
|
"properties" => properties(xml.xpath("/map")),
|
34
34
|
"layers" => map_layers(xml),
|
35
|
-
"tilesets" => map_tilesets(xml)
|
35
|
+
"tilesets" => map_tilesets(xml),
|
36
|
+
"object_groups" => map_object_groups(xml),
|
37
|
+
"image_layers" => map_image_layers(xml)
|
36
38
|
}
|
37
39
|
end
|
38
40
|
|
@@ -133,8 +135,64 @@ module Tmx
|
|
133
135
|
"properties" => properties(xml)
|
134
136
|
}
|
135
137
|
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def map_object_groups(xml)
|
141
|
+
xml.xpath("map/objectgroup").map do |object_group|
|
142
|
+
|
143
|
+
objects = object_group.xpath("object").map do |object|
|
144
|
+
properties = {
|
145
|
+
"name" => object.xpath("@name").text,
|
146
|
+
"type" => object.xpath("@type").text,
|
147
|
+
"x" => object.xpath("@x").text.to_i,
|
148
|
+
"y" => object.xpath("@y").text.to_i,
|
149
|
+
"width" => object.xpath("@width").text.to_i,
|
150
|
+
"height" => object.xpath("@height").text.to_i,
|
151
|
+
"visible" => (object.xpath("@visible").text =~ /^false$/ ? false : true),
|
152
|
+
"properties" => properties(object)
|
153
|
+
}
|
154
|
+
|
155
|
+
properties.merge(object_shape(object))
|
156
|
+
end
|
157
|
+
|
158
|
+
{
|
159
|
+
"name" => object_group.xpath("@name").text,
|
160
|
+
"width" => object_group.xpath("@width").text.to_i,
|
161
|
+
"height" => object_group.xpath("@height").text.to_i,
|
162
|
+
"opacity" => (object_group.xpath("@opacity").text == "" ? 1.0 : object_group.xpath("@opacity").text.to_f),
|
163
|
+
"objects" => objects
|
164
|
+
}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def object_shape(object)
|
169
|
+
if not object.xpath("ellipse").empty?
|
170
|
+
{ "shape" => "ellipse" }
|
171
|
+
elsif not object.xpath("polyline").empty?
|
172
|
+
points = object.xpath("polyline/@points").text.split(" ")
|
173
|
+
{ "shape" => "polyline", "points" => points }
|
174
|
+
elsif not object.xpath("polygon").empty?
|
175
|
+
points = object.xpath("polygon/@points").text.split(" ")
|
176
|
+
{ "shape" => "polygon", "points" => points }
|
177
|
+
else
|
178
|
+
x = object.xpath("@x").text.to_i
|
179
|
+
y = object.xpath("@y").text.to_i
|
180
|
+
width = object.xpath("@width").text.to_i
|
181
|
+
height = object.xpath("@height").text.to_i
|
182
|
+
{ "shape" => "polygon", "points" => [ "#{x},#{y}", "#{x + width},#{y}", "#{x + width},#{y + height}", "#{x},#{y + height}" ] }
|
183
|
+
end
|
184
|
+
end
|
136
185
|
|
186
|
+
def map_image_layers(xml)
|
187
|
+
xml.xpath("map/imagelayer").map do |image_layer|
|
137
188
|
|
189
|
+
{
|
190
|
+
"name" => image_layer.xpath("@name").text,
|
191
|
+
"width" => image_layer.xpath("@width").text.to_i,
|
192
|
+
"height" => image_layer.xpath("@height").text.to_i
|
193
|
+
}
|
194
|
+
|
195
|
+
end
|
138
196
|
end
|
139
197
|
|
140
198
|
end
|
data/lib/tmx/version.rb
CHANGED
@@ -15,8 +15,8 @@ describe Tmx, "JSON Format" do
|
|
15
15
|
its(:height) { should eq 12 }
|
16
16
|
its(:width) { should eq 16 }
|
17
17
|
|
18
|
-
its(:tileheight) { should eq
|
19
|
-
its(:tilewidth) { should eq
|
18
|
+
its(:tileheight) { should eq 32 }
|
19
|
+
its(:tilewidth) { should eq 32 }
|
20
20
|
|
21
21
|
its(:orientation) { should eq "orthogonal" }
|
22
22
|
|
@@ -39,7 +39,7 @@ describe Tmx, "JSON Format" do
|
|
39
39
|
|
40
40
|
let(:subject) { map.layers.first }
|
41
41
|
|
42
|
-
its(:name) { should eq "
|
42
|
+
its(:name) { should eq "Layer" }
|
43
43
|
its(:opacity) { should eq 1 }
|
44
44
|
its(:type) { should eq "tilelayer" }
|
45
45
|
its(:visible) { should be_true }
|
@@ -48,7 +48,7 @@ describe Tmx, "JSON Format" do
|
|
48
48
|
its(:x) { should eq 0 }
|
49
49
|
its(:y) { should eq 0 }
|
50
50
|
|
51
|
-
its(:data) { should eq [
|
51
|
+
its(:data) { should eq [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 142, 20, 0, 0, 0, 141, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0, 0, 25, 26, 27, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 65, 0, 0, 8, 8, 8, 23, 0, 80, 0, 137, 138, 0, 0, 0, 0, 83, 0, 0, 0, 0, 50, 0, 0, 80, 0, 191, 192, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 19, 37, 38, 37, 37, 37, 38, 37, 37, 37, 37, 37, 19, 37, 37, 37, 37, 37, 37, 37, 37] }
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -62,14 +62,122 @@ describe Tmx, "JSON Format" do
|
|
62
62
|
|
63
63
|
its(:firstgid) { should eq 1 }
|
64
64
|
its(:image) { should eq "tiles.png" }
|
65
|
-
its(:imageheight) { should eq
|
66
|
-
its(:imagewidth) { should eq
|
67
|
-
its(:margin) { should eq
|
65
|
+
its(:imageheight) { should eq 400 }
|
66
|
+
its(:imagewidth) { should eq 640 }
|
67
|
+
its(:margin) { should eq 2 }
|
68
68
|
its(:name) { should eq "tiles" }
|
69
|
-
its(:spacing) { should eq
|
70
|
-
its(:tileheight) { should eq
|
71
|
-
its(:tilewidth) { should eq
|
72
|
-
its(:properties) { should eq({}) }
|
69
|
+
its(:spacing) { should eq 2 }
|
70
|
+
its(:tileheight) { should eq 32 }
|
71
|
+
its(:tilewidth) { should eq 32 }
|
72
|
+
its(:properties) { should eq({ "alpha" => "1" }) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#object_groups' do
|
77
|
+
it "has the correct number of object groups" do
|
78
|
+
expect(subject.object_groups).to have(1).item
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when evaluating the first object group" do
|
82
|
+
|
83
|
+
let(:subject) { map.object_groups.first }
|
84
|
+
|
85
|
+
its(:name) { should eq "Objects" }
|
86
|
+
its(:width) { should eq 16 }
|
87
|
+
its(:height) { should eq 12 }
|
88
|
+
its(:objects) { should have(6).items }
|
89
|
+
its(:opacity) { should eq 1 }
|
90
|
+
|
91
|
+
context "when evaluating a rectangluar object" do
|
92
|
+
let(:subject) { map.object_groups.first.objects.first }
|
93
|
+
|
94
|
+
its(:name) { should eq "ground" }
|
95
|
+
its(:type) { should eq "floor" }
|
96
|
+
its(:x) { should eq 0 }
|
97
|
+
its(:y) { should eq 256 }
|
98
|
+
its(:width) { should eq 512 }
|
99
|
+
its(:height) { should eq 32 }
|
100
|
+
its(:visible) { should be_true }
|
101
|
+
|
102
|
+
its(:properties) { should have(1).item }
|
103
|
+
|
104
|
+
its(:shape) { should eq "polygon" }
|
105
|
+
its(:points) { should eq [ "0,256", "512,256", "512,288", "0,288" ]}
|
106
|
+
|
107
|
+
it "has the correct properties" do
|
108
|
+
expect(subject.properties["type"]).to eq "sand"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when evaluating a circular object" do
|
113
|
+
|
114
|
+
let(:subject) { map.object_groups.first.objects[2] }
|
115
|
+
|
116
|
+
its(:name) { should eq "mushroom" }
|
117
|
+
its(:type) { should eq "mushroom" }
|
118
|
+
its(:x) { should eq 256 }
|
119
|
+
its(:y) { should eq 224 }
|
120
|
+
its(:width) { should eq 32 }
|
121
|
+
its(:height) { should eq 32 }
|
122
|
+
its(:visible) { should be_true }
|
123
|
+
|
124
|
+
its(:properties) { should have(1).item }
|
125
|
+
|
126
|
+
its(:shape) { should eq "ellipse" }
|
127
|
+
|
128
|
+
it "has the correct properties" do
|
129
|
+
expect(subject.properties["player.life.bonus"]).to eq "1"
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when evaluating a polygon (triangle)" do
|
135
|
+
|
136
|
+
let(:subject) { map.object_groups.first.objects[3] }
|
137
|
+
|
138
|
+
its(:name) { should eq "danger" }
|
139
|
+
its(:type) { should eq "sign" }
|
140
|
+
its(:x) { should eq 448 }
|
141
|
+
its(:y) { should eq 192 }
|
142
|
+
its(:shape) { should eq "polygon" }
|
143
|
+
its(:points) { should eq [ "0,0", "32,64", "-32,64", "0,0"] }
|
144
|
+
its(:visible) { should be_true }
|
145
|
+
|
146
|
+
its(:properties) { should have(0).items }
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when evaluating a polyline (line segments)" do
|
151
|
+
|
152
|
+
let(:subject) { map.object_groups.first.objects[4] }
|
153
|
+
|
154
|
+
its(:name) { should eq "dirt" }
|
155
|
+
its(:type) { should eq "underground" }
|
156
|
+
its(:x) { should eq 32 }
|
157
|
+
its(:y) { should eq 320 }
|
158
|
+
its(:visible) { should be_true }
|
159
|
+
|
160
|
+
its(:properties) { should have(3).items }
|
161
|
+
|
162
|
+
its(:shape) { should eq "polyline" }
|
163
|
+
its(:points) { should eq ["0,0", "448,0", "448,64", "0,64", "0,0"]}
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
describe '#image_layers' do
|
171
|
+
it "has the correct number of image layers" do
|
172
|
+
expect(subject.image_layers).to have(1).item
|
173
|
+
end
|
174
|
+
|
175
|
+
context "when evaluating the first image layer" do
|
176
|
+
let(:subject) { map.image_layers.first }
|
177
|
+
|
178
|
+
its(:name) { should eq "Image Layer" }
|
179
|
+
its(:width) { should eq 16 }
|
180
|
+
its(:height) { should eq 12 }
|
73
181
|
end
|
74
182
|
end
|
75
183
|
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# require 'spec_helper'
|
2
|
+
|
3
|
+
# describe Tmx, "JSON Format" do
|
4
|
+
|
5
|
+
# let(:fixture_file) { File.join File.dirname(__FILE__), "..", "fixtures", "map-isometric.json" }
|
6
|
+
|
7
|
+
# let(:map) do
|
8
|
+
# described_class.load(fixture_file)
|
9
|
+
# end
|
10
|
+
|
11
|
+
# let(:subject) { map }
|
12
|
+
|
13
|
+
# its(:version) { should eq 1 }
|
14
|
+
|
15
|
+
# its(:height) { should eq 12 }
|
16
|
+
# its(:width) { should eq 16 }
|
17
|
+
|
18
|
+
# its(:tileheight) { should eq 50 }
|
19
|
+
# its(:tilewidth) { should eq 50 }
|
20
|
+
|
21
|
+
# its(:orientation) { should eq "orthogonal" }
|
22
|
+
|
23
|
+
# describe '#properties' do
|
24
|
+
# it "has the correct number of properties" do
|
25
|
+
# expect(subject.properties).to have(1).item
|
26
|
+
# end
|
27
|
+
|
28
|
+
# it "property values are correct" do
|
29
|
+
# expect(subject.properties["hero.position"]).to eq "400,525,1"
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
|
33
|
+
# describe '#layers' do
|
34
|
+
# it "has the correct number of layers" do
|
35
|
+
# expect(subject.layers).to have(1).item
|
36
|
+
# end
|
37
|
+
|
38
|
+
# context "when evaluating the first layer" do
|
39
|
+
|
40
|
+
# let(:subject) { map.layers.first }
|
41
|
+
|
42
|
+
# its(:name) { should eq "Tile Layer 1" }
|
43
|
+
# its(:opacity) { should eq 1 }
|
44
|
+
# its(:type) { should eq "tilelayer" }
|
45
|
+
# its(:visible) { should be_true }
|
46
|
+
# its(:height) { should eq 12 }
|
47
|
+
# its(:width) { should eq 16 }
|
48
|
+
# its(:x) { should eq 0 }
|
49
|
+
# its(:y) { should eq 0 }
|
50
|
+
|
51
|
+
# its(:data) { should eq [ 3, 3, 3, 3, 3, 3, 2, 5, 5, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 4, 4, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 4, 4, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 4, 4, 7, 18, 9, 9, 17, 3, 3, 3, 3, 3, 3, 3, 3, 2, 4, 4, 15, 14, 4, 6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 2, 4, 4, 4, 4, 4, 6, 7, 3, 3, 3, 3, 3, 18, 9, 17, 2, 4, 4, 10, 13, 4, 10, 11, 3, 3, 3, 3, 18, 14, 6, 7, 2, 4, 4, 7, 16, 8, 11, 3, 3, 3, 3, 3, 2, 4, 4, 15, 14, 4, 4, 7, 3, 3, 3, 3, 3, 3, 3, 3, 2, 4, 4, 4, 4, 4, 4, 7, 3, 3, 3, 3, 3, 3, 3, 3, 16, 8, 8, 8, 13, 4, 4, 7, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 12, 12, 16, 8, 8, 11, 3, 3, 3, 3, 3, 3] }
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
|
55
|
+
# describe '#tilesets' do
|
56
|
+
# it "has the correct number of tilesets" do
|
57
|
+
# expect(subject.tilesets).to have(1).item
|
58
|
+
# end
|
59
|
+
|
60
|
+
# context "when evaluating the first tileset" do
|
61
|
+
# let(:subject) { map.tilesets.first }
|
62
|
+
|
63
|
+
# its(:firstgid) { should eq 1 }
|
64
|
+
# its(:image) { should eq "tiles.png" }
|
65
|
+
# its(:imageheight) { should eq 250 }
|
66
|
+
# its(:imagewidth) { should eq 200 }
|
67
|
+
# its(:margin) { should eq 0 }
|
68
|
+
# its(:name) { should eq "tiles" }
|
69
|
+
# its(:spacing) { should eq 0 }
|
70
|
+
# its(:tileheight) { should eq 50 }
|
71
|
+
# its(:tilewidth) { should eq 50 }
|
72
|
+
# its(:properties) { should eq({}) }
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
|
76
|
+
# end
|