tmx 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OGY5ZWFiM2U3NWQ1M2NjYzUxYzI3ODkxNTMyMTllZWFmZDA1YzM1Nw==
4
+ OTA3ZjIyZjNjZGZhYTg0ZGVjNWY0NjkyZDQ2MjcwYTM2YmRkZmY3NA==
5
5
  data.tar.gz: !binary |-
6
- ZGZhODNjYzFjYWMzMjc5ZmZlZGMxNWVjODY4MGUzODYzZmNhZjRmYw==
6
+ ODA2YWY5OTJjN2FiMzFlOTYyN2M3YWIwODgxY2Q5ODc4MjQ2ZDRlNQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MjZjZDljYzVmZmM5ODJjNGYzNzRiNmEyMzZiYzcxOTRhZmZjODI0MjQ0MjA1
10
- ZmYxMmNmOTA1Zjc5MmI1NGEzYWFjNWUxYTdjMjhiZTViYzg2Y2QyNzAyMjRh
11
- OTUwZDk3NmQwOTViYWRlZjk2OWQwZWVhNjRlNzZhODA5OGJhYzk=
9
+ MjBlM2NhZTU3OTZjYzZkZjcyMjU4ZmVhNjIyNDE1ZjFlMjY1OTgwMzIwMzFk
10
+ Y2NjYTE1Mjg4NGMzNjZiYzc5OTc5M2M0M2Y5ZDM1NGRhYWRiNzg3ODQ3ZjQ0
11
+ YTc0NmQzNjU5NDU4ZDI5NTNlYTkwZTViZjMzOTFhNTQ2ZGM4ZjY=
12
12
  data.tar.gz: !binary |-
13
- MWU1Y2QxMzEyOWY5MDJjOWUzMjU5NjcyZDY0ZWRmZWYxODNmNzU2MjczZTc1
14
- N2QxNjQyZmU1MGZjNTQzZmVkY2I1NWI4MzBjNmY5NzkyMTQ0OWRlNWJkZTY3
15
- MWZjMjRiM2MwMzFhOTkyNTNhMzI5YWNmNjM5NmIxZTAwZjNhNWM=
13
+ ODIyZGIzNmJkOTI2NzExZTc0YzA3YmJjMzdiNzY3YjA5NzM2NTExMTliMzIw
14
+ NGRmN2M0ZDgyMTg4Yzk0YTc4ZGMxY2Q5OWY3MTMwOThiNDkyOTIwOThhYTlm
15
+ OTQ1MzQ2ZWRlNzE3MmQyYzkyM2RmOTI3NDRmNzk3YTlmYjAzMDI=
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tmx
2
2
 
3
- A library for parsing the **[Tiled Map Editor](http://www.mapeditor.org/)** file format.
3
+ A library for parsing the **[Tiled Map Editor](http://www.mapeditor.org/)** file format (version 0.9).
4
4
 
5
5
  ## Support
6
6
 
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ module Tmx
2
+ class ImageLayer < OpenStruct
3
+
4
+ end
5
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+ module Tmx
2
+ class Object < OpenStruct
3
+
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Tmx
2
+ class ObjectGroup < OpenStruct
3
+
4
+ def objects
5
+ Array(contents['objects']).map {|object| Tmx::Object.new(object.merge(contents: object)) }
6
+ end
7
+
8
+ end
9
+ end
@@ -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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Tmx
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -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 50 }
19
- its(:tilewidth) { should eq 50 }
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 "Tile Layer 1" }
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 [ 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] }
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 250 }
66
- its(:imagewidth) { should eq 200 }
67
- its(:margin) { should eq 0 }
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 0 }
70
- its(:tileheight) { should eq 50 }
71
- its(:tilewidth) { should eq 50 }
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