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 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