dxruby_tiled 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.ja.md +10 -19
- data/README.md +7 -14
- data/dxruby_tiled.gemspec +7 -9
- data/examples/dxruby_tiled_test.rb +226 -54
- data/lib/dxruby_tiled.rb +35 -10
- data/lib/dxruby_tiled/grouplayer.rb +30 -0
- data/lib/dxruby_tiled/imagelayer.rb +40 -24
- data/lib/dxruby_tiled/layer.rb +17 -40
- data/lib/dxruby_tiled/layer_hexagonal.rb +97 -94
- data/lib/dxruby_tiled/layer_isometric.rb +33 -46
- data/lib/dxruby_tiled/layer_orthogonal.rb +29 -29
- data/lib/dxruby_tiled/layer_staggered.rb +80 -77
- data/lib/dxruby_tiled/map.rb +67 -51
- data/lib/dxruby_tiled/object.rb +263 -0
- data/lib/dxruby_tiled/objectgroup.rb +36 -15
- data/lib/dxruby_tiled/tile.rb +139 -0
- data/lib/dxruby_tiled/tilelayer.rb +116 -0
- data/lib/dxruby_tiled/tileset.rb +100 -27
- data/lib/dxruby_tiled/tilesets.rb +49 -15
- data/lib/dxruby_tiled/tmx_loader.rb +271 -0
- data/lib/dxruby_tiled/version.rb +1 -1
- metadata +29 -24
- data/LICENSE +0 -21
@@ -0,0 +1,116 @@
|
|
1
|
+
module DXRuby
|
2
|
+
module Tiled
|
3
|
+
class TileLayer < Layer
|
4
|
+
attr_reader :width, :height, :startx, :starty
|
5
|
+
|
6
|
+
def initialize(data, map)
|
7
|
+
super
|
8
|
+
if data[:chunks]
|
9
|
+
@x1 = data[:chunks].map {|chunk| chunk[:x] }.min
|
10
|
+
@y1 = data[:chunks].map {|chunk| chunk[:y] }.min
|
11
|
+
@x2 = data[:chunks].map {|chunk| chunk[:x] + chunk[:width ] }.max
|
12
|
+
@y2 = data[:chunks].map {|chunk| chunk[:y] + chunk[:height] }.max
|
13
|
+
@data = Array.new((@x2 - @x1) * (@y2 - @y1), 0)
|
14
|
+
data[:chunks].each do |chunk|
|
15
|
+
get_data(chunk[:data], data[:encoding], data[:compression]).each_with_index do |d, i|
|
16
|
+
x, y = chunk[:x] + i % chunk[:width] - @x1, chunk[:y] + i / chunk[:width] - @y1
|
17
|
+
@data[y * (@x2 - @x1) + x] = d
|
18
|
+
end
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@x1 = data[:startx] || 0
|
22
|
+
@y1 = data[:starty] || 0
|
23
|
+
@x2 = @x1 + (data[:width ] || map.width )
|
24
|
+
@y2 = @y1 + (data[:height] || map.height)
|
25
|
+
@data = get_data(data[:data], data[:encoding], data[:compression])
|
26
|
+
end
|
27
|
+
@startx = @x1
|
28
|
+
@starty = @y1
|
29
|
+
@width = @x2 - @x1
|
30
|
+
@height = @y2 - @y1
|
31
|
+
@tile_width = map.tile_width
|
32
|
+
@tile_height = map.tile_height
|
33
|
+
@renderorder_x = map.renderorder_x
|
34
|
+
@renderorder_y = map.renderorder_y
|
35
|
+
@render_target = DXRuby::RenderTarget.new(DXRuby::Window.width, DXRuby::Window.height)
|
36
|
+
@tilesets = map.tilesets
|
37
|
+
|
38
|
+
self.extend LoopTileLayer if map.loop
|
39
|
+
end
|
40
|
+
|
41
|
+
def [](x, y)
|
42
|
+
x < @x1 || x >= @x2 || y < @y1 || y >= @y2 ?
|
43
|
+
0 : @data[(y - @y1) * @width + x - @x1]
|
44
|
+
end
|
45
|
+
|
46
|
+
def []=(x, y, value)
|
47
|
+
return if x < @x1 || x >= @x2 || y < @y1 || y >= @y2
|
48
|
+
@data[(y - @y1) * @width + x - @x1] = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def include?(x, y)
|
52
|
+
x >= @x1 && x < @x2 && y >= @y1 && y < @y2
|
53
|
+
end
|
54
|
+
alias_method :member?, :include?
|
55
|
+
|
56
|
+
def at(pos_x, pos_y)
|
57
|
+
x, y = xy_at(pos_x, pos_y)
|
58
|
+
self[x, y]
|
59
|
+
end
|
60
|
+
|
61
|
+
def change_at(pos_x, pos_y, value)
|
62
|
+
x, y = xy_at(pos_x, pos_y)
|
63
|
+
self[x, y] = value
|
64
|
+
end
|
65
|
+
|
66
|
+
def tile_at(pos_x, pos_y)
|
67
|
+
@tilesets[at(pos_x, pos_y)]
|
68
|
+
end
|
69
|
+
|
70
|
+
def render(pos_x, pos_y, target = DXRuby::Window, z = 0, offset_x = 0, offset_y = 0, opacity = 1.0)
|
71
|
+
unless @render_target.width == target.width && @render_target.height == target.height
|
72
|
+
@render_target.resize(target.width, target.height)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
alias_method :draw, :render
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def get_data(data, encoding, compression)
|
80
|
+
case encoding
|
81
|
+
when "base64"
|
82
|
+
tmp = Base64.decode64(data)
|
83
|
+
case compression
|
84
|
+
when "gzip" # unsupported
|
85
|
+
raise NotImplementedError.new("GZip is unsupported.")
|
86
|
+
when "zlib"
|
87
|
+
data_array = Zlib::Inflate.inflate(tmp).unpack("L*")
|
88
|
+
else
|
89
|
+
data_array = tmp.unpack("L*")
|
90
|
+
end
|
91
|
+
else
|
92
|
+
data_array = data
|
93
|
+
end
|
94
|
+
data_array
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
module LoopTileLayer
|
99
|
+
def [](x, y)
|
100
|
+
@data[((y - @y1) % @height) * @width + ((x - @x1) % @width)]
|
101
|
+
end
|
102
|
+
|
103
|
+
def []=(x, y, value)
|
104
|
+
@data[((y - @y1) % @height) * @width + ((x - @x1) % @width)] = value
|
105
|
+
end
|
106
|
+
|
107
|
+
def include?(x, y)
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
def member?(x, y)
|
112
|
+
true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/dxruby_tiled/tileset.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module DXRuby
|
2
2
|
module Tiled
|
3
3
|
class Tileset
|
4
|
-
attr_reader :firstgid, :name, :tile_width, :tile_height,
|
4
|
+
attr_reader :firstgid, :source, :name, :tile_width, :tile_height,
|
5
5
|
:spacing, :margin, :tile_count, :columns, :tile_offset, :properties,
|
6
|
-
:
|
6
|
+
:tiles, :animations
|
7
7
|
|
8
8
|
def initialize(data, map)
|
9
|
-
@
|
10
|
-
@
|
9
|
+
@firstgid = data[:firstgid] || 1
|
10
|
+
@source = data[:source]
|
11
|
+
data_dir = @source ? File.dirname(@source) : map.data_dir
|
12
|
+
data = map.load_tileset(@source) if @source
|
11
13
|
|
12
|
-
@firstgid = data[:firstgid] || 1
|
13
14
|
@name = data[:name]
|
14
15
|
@tile_width = data[:tilewidth] || map.tile_width
|
15
16
|
@tile_height = data[:tileheight] || map.tile_height
|
@@ -17,18 +18,62 @@ module DXRuby
|
|
17
18
|
@margin = data[:margin] || 0
|
18
19
|
@tile_count = data[:tilecount]
|
19
20
|
@columns = data[:columns]
|
20
|
-
@tile_offset = data[:tileoffset]
|
21
|
+
@tile_offset = data[:tileoffset] || { x: 0, y: 0 }
|
21
22
|
@properties = data[:properties] || {}
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
image.
|
24
|
+
@tiles = []
|
25
|
+
tile_images = []
|
26
|
+
if data[:image]
|
27
|
+
image = map.load_image(data[:image], data[:transparentcolor], data_dir)
|
28
|
+
image_width = data[:imagewidth] || image.width
|
29
|
+
image_height = data[:imageheight] || image.height
|
30
|
+
tile_images = split_image(image, image_width, image_height)
|
31
|
+
image.dispose()
|
32
|
+
else
|
33
|
+
data[:tiles].each_pair do |key, value|
|
34
|
+
tile_images[key.to_s.to_i] = map.load_image(value[:image], nil, data_dir)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@tile_count = tile_images.size unless @tile_count
|
38
|
+
|
39
|
+
adjusted_offset_x = map.orientation == IsometricLayer ? map.tile_width / 2 : 0
|
40
|
+
adjusted_offset_y = @tile_offset[:y] + map.tile_height
|
41
|
+
tile_images.each_with_index do |image, i|
|
42
|
+
next unless image
|
43
|
+
@tiles[i] = Tile.new(
|
44
|
+
image,
|
45
|
+
@tile_offset[:x] - adjusted_offset_x,
|
46
|
+
@tile_offset[:y], adjusted_offset_y - image.height,
|
47
|
+
self
|
48
|
+
)
|
27
49
|
end
|
28
|
-
image_width = data[:imagewidth] || image.width
|
29
|
-
image_height = data[:imageheight] || image.height
|
30
50
|
|
31
|
-
|
51
|
+
tiles_data = data[:tiles] || {}
|
52
|
+
set_types(tiles_data)
|
53
|
+
set_animations(tiles_data)
|
54
|
+
set_collisions(tiles_data)
|
55
|
+
end
|
56
|
+
|
57
|
+
def dispose()
|
58
|
+
@tiles.each_value do |tile|
|
59
|
+
@tile.image.dispose()
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def delayed_dispose()
|
64
|
+
@tiles.each_value do |tile|
|
65
|
+
@tile.image.delayed_dispose()
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def disposed?()
|
70
|
+
@tiles[0].image.disposed?()
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def split_image(image, image_width, image_height)
|
76
|
+
tile_images = []
|
32
77
|
i = 0
|
33
78
|
col = 1
|
34
79
|
x = @margin
|
@@ -41,31 +86,59 @@ module DXRuby
|
|
41
86
|
end
|
42
87
|
break if y + @tile_height > image_height
|
43
88
|
|
44
|
-
|
89
|
+
tile_images[i] = image.slice(x, y, @tile_width, @tile_height)
|
45
90
|
x += @tile_width + @spacing
|
46
91
|
i += 1
|
47
92
|
col += 1
|
48
93
|
break if @tile_count && i >= @tile_count
|
49
94
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
95
|
+
tile_images
|
96
|
+
end
|
97
|
+
|
98
|
+
def set_types(tiles_data)
|
99
|
+
tiles_data.each_pair do |key, value|
|
100
|
+
next unless value.has_key?(:type)
|
101
|
+
@tiles[key.to_s.to_i].type = value[:type]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def set_animations(tiles_data)
|
106
|
+
@animations = []
|
107
|
+
tiles_data.each_pair do |key, value|
|
55
108
|
next unless value.has_key?(:animation)
|
56
|
-
anim_time
|
57
|
-
|
58
|
-
time = 0
|
109
|
+
anim_time = [0]
|
110
|
+
anim_tile = []
|
59
111
|
value[:animation].each do |anim|
|
60
|
-
anim_time.push(
|
61
|
-
|
62
|
-
time += anim[:duration]
|
112
|
+
anim_time.push(anim_time.last + anim[:duration])
|
113
|
+
anim_tile.push(@tiles[anim[:tileid]])
|
63
114
|
end
|
64
|
-
|
65
|
-
@animations
|
115
|
+
@tiles[key.to_s.to_i].set_animation(anim_time, anim_tile)
|
116
|
+
@animations.push(key.to_s.to_i)
|
66
117
|
end
|
67
118
|
end
|
68
119
|
|
120
|
+
def set_collisions(tiles_data)
|
121
|
+
tiles_data.each_pair do |key, value|
|
122
|
+
next unless value.has_key?(:objectgroup)
|
123
|
+
next unless value[:objectgroup].has_key?(:objects)
|
124
|
+
collision = []
|
125
|
+
value[:objectgroup][:objects].each do |obj|
|
126
|
+
case
|
127
|
+
when obj[:ellipse]
|
128
|
+
collision.push([obj[:x], obj[:y], (obj[:width] + obj[:height]) / 2])
|
129
|
+
when obj[:polygon]
|
130
|
+
(obj[:polygon].size - 2).times do |i|
|
131
|
+
collision.push([obj[:polygon][0 ][:x], obj[:polygon][0 ][:y],
|
132
|
+
obj[:polygon][i + 1][:x], obj[:polygon][i + 1][:y],
|
133
|
+
obj[:polygon][i + 2][:x], obj[:polygon][i + 2][:y]])
|
134
|
+
end
|
135
|
+
else
|
136
|
+
collision.push([obj[:x], obj[:y], obj[:x] + obj[:width], obj[:y] + obj[:height]])
|
137
|
+
end
|
138
|
+
end
|
139
|
+
@tiles[key.to_s.to_i].collision = collision
|
140
|
+
end
|
141
|
+
end
|
69
142
|
end
|
70
143
|
end
|
71
144
|
end
|
@@ -1,34 +1,68 @@
|
|
1
1
|
module DXRuby
|
2
2
|
module Tiled
|
3
3
|
class Tilesets
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :tiles, :tile_left, :tile_right, :tile_top, :tile_bottom
|
5
5
|
|
6
6
|
def initialize(data, map)
|
7
|
-
@data = data
|
8
|
-
@map = map
|
9
|
-
|
10
7
|
@last_time = 0
|
11
|
-
@
|
12
|
-
|
13
|
-
|
8
|
+
@tiles = {}
|
9
|
+
dummy_tile = Tile.new(DXRuby::Image.new(map.tile_width, map.tile_height), 0, 0, 0)
|
10
|
+
def dummy_tile.render(x, y, target = DXRuby::Window, z_index = 0); end
|
11
|
+
def dummy_tile.draw(x, y, target = DXRuby::Window, z_index = 0); end
|
12
|
+
@tiles[0] = dummy_tile
|
13
|
+
@tiles.default = dummy_tile
|
14
14
|
|
15
|
+
@animations = []
|
16
|
+
@tilesets = data.map { |tileset| Tileset.new(tileset, map) }
|
17
|
+
hex = map.orientation == HexagonalLayer
|
15
18
|
@tilesets.each do |tileset|
|
16
|
-
gid = tileset.firstgid
|
17
|
-
tileset.
|
18
|
-
|
19
|
+
gid = tileset.firstgid
|
20
|
+
tileset.tiles.each_with_index do |tile, i|
|
21
|
+
next unless tile
|
22
|
+
@tiles[gid + i] = tile
|
23
|
+
range = hex ? 1..15 : 1..7
|
24
|
+
k = hex ? 0x10000000 : 0x20000000
|
25
|
+
range.each do |j|
|
26
|
+
tileid = j * k + gid + i
|
27
|
+
@tiles[tileid] = FlippedTile.new(tile, tileid, hex)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
tileset.animations.each { |i| @animations.push(gid + i) }
|
19
31
|
end
|
32
|
+
@tile_left = @tiles.values.map { |tile| tile.offset_x }.min
|
33
|
+
@tile_top = @tiles.values.map { |tile| tile.offset_y }.min
|
34
|
+
@tile_right = @tiles.values.map { |tile| tile.offset_x + tile.width }.max
|
35
|
+
@tile_bottom = @tiles.values.map { |tile| tile.offset_y + tile.height }.max
|
36
|
+
end
|
37
|
+
|
38
|
+
def [](num)
|
39
|
+
@tiles[num]
|
20
40
|
end
|
21
41
|
|
22
|
-
def
|
42
|
+
def animate()
|
23
43
|
return if @last_time == DXRuby::Window::running_time
|
24
44
|
@last_time = DXRuby::Window::running_time
|
25
45
|
|
26
|
-
@animations.
|
27
|
-
|
28
|
-
|
29
|
-
|
46
|
+
@animations.each { |i| @tiles[i].animate!(@last_time) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def gid_adjusted_by_source(gid, source)
|
50
|
+
gid + @tilesets.find { |tileset| tileset.source == source }.firstgid - 1
|
30
51
|
end
|
31
52
|
|
53
|
+
def dispose()
|
54
|
+
@tilesets.each_value { |tileset| tileset.dispose() }
|
55
|
+
@tiles[0].image.dispose()
|
56
|
+
end
|
57
|
+
|
58
|
+
def delayed_dispose()
|
59
|
+
@tilesets.each_value { |tileset| tileset.delayed_dispose() }
|
60
|
+
@tiles[0].image.delayed_dispose()
|
61
|
+
end
|
62
|
+
|
63
|
+
def disposed?()
|
64
|
+
@tiles[0].image.disposed?()
|
65
|
+
end
|
32
66
|
end
|
33
67
|
end
|
34
68
|
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
require "dxruby_tiled"
|
2
|
+
require "rexml/document"
|
3
|
+
|
4
|
+
module DXRuby
|
5
|
+
module Tiled
|
6
|
+
module TMXLoader
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def load_tmx(tmxfile, encoding = Encoding::UTF_8, dir = nil)
|
10
|
+
Map.new(
|
11
|
+
TMXLoader.tmx_to_hash(TMXLoader.read_xmlfile(tmxfile, encoding)),
|
12
|
+
dir || File.dirname(tmxfile)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def read_xmlfile(xmlfile, encoding = Encoding::UTF_8)
|
17
|
+
REXML::Document.new(DXRuby::Tiled.read_file(xmlfile, encoding))
|
18
|
+
end
|
19
|
+
|
20
|
+
def element_to_hash(elm, attrs_i = [], attrs_f = [], attrs_b = [])
|
21
|
+
hash = {}
|
22
|
+
|
23
|
+
elm.attributes.each_pair do |key, value|
|
24
|
+
str = value.to_s
|
25
|
+
if attrs_i.include?(key)
|
26
|
+
hash[key.to_sym] = str.to_i
|
27
|
+
elsif attrs_f.include?(key)
|
28
|
+
hash[key.to_sym] = str.to_f
|
29
|
+
elsif attrs_b.include?(key)
|
30
|
+
hash[key.to_sym] = !!str && str != "0" && str != "false"
|
31
|
+
else
|
32
|
+
hash[key.to_sym] = str
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def properties_parent_to_hash(element)
|
40
|
+
properties_hash = { properties: {}, propertytypes: {} }
|
41
|
+
|
42
|
+
element.each_element("properties") do |properties|
|
43
|
+
properties.each_element_with_attribute("type") do |property|
|
44
|
+
name = property.attribute("name" ).to_s.to_sym
|
45
|
+
type = property.attribute("type" ).to_s
|
46
|
+
value = property.attribute("value").to_s
|
47
|
+
case type
|
48
|
+
when "string", "color", "file"
|
49
|
+
properties_hash[:properties][name] = value
|
50
|
+
when "int"
|
51
|
+
properties_hash[:properties][name] = value.to_i
|
52
|
+
when "float"
|
53
|
+
properties_hash[:properties][name] = value.to_f
|
54
|
+
when "bool"
|
55
|
+
properties_hash[:properties][name] = !!value && value != "0" && value != "false"
|
56
|
+
end
|
57
|
+
properties_hash[:propertytypes][name] = type
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
properties_hash[:properties].empty? ? {} : properties_hash
|
62
|
+
end
|
63
|
+
|
64
|
+
def tileset_to_hash(tileset_element)
|
65
|
+
tileset_hash = element_to_hash(tileset_element,
|
66
|
+
%w[firstgid tilewidth tileheight spacing margin tilecount columns]
|
67
|
+
)
|
68
|
+
tileset_hash.merge!(properties_parent_to_hash(tileset_element))
|
69
|
+
tileset_element.each_element("tileoffset") do |tileoffset|
|
70
|
+
tileset_hash[:tileoffset] = {
|
71
|
+
x: tileoffset.attribute("x").to_s.to_i,
|
72
|
+
y: tileoffset.attribute("y").to_s.to_i
|
73
|
+
}
|
74
|
+
end
|
75
|
+
tileset_element.each_element("image") do |image_element|
|
76
|
+
tileset_hash.merge!(image_to_hash(image_element))
|
77
|
+
end
|
78
|
+
tileset_hash[:tiles] = {}
|
79
|
+
tileset_element.each_element("tile") do |tile_element|
|
80
|
+
hash = element_to_hash(tile_element)
|
81
|
+
tile_hash = { type: hash[:type] }
|
82
|
+
tile_element.each_element("image") do |image_element|
|
83
|
+
tile_hash.merge!(image_to_hash(image_element))
|
84
|
+
end
|
85
|
+
tile_element.each_element("objectgroup") do |objectgroup_element|
|
86
|
+
tile_hash[:objectgroup] = objectgroup_to_hash(objectgroup_element)
|
87
|
+
end
|
88
|
+
tile_element.each_element("animation") do |animation_element|
|
89
|
+
tile_hash[:animation] = animation_to_array(animation_element)
|
90
|
+
end
|
91
|
+
tileset_hash[:tiles][hash[:id]] = tile_hash
|
92
|
+
end
|
93
|
+
|
94
|
+
tileset_hash
|
95
|
+
end
|
96
|
+
|
97
|
+
def image_to_hash(image_element)
|
98
|
+
hash = {}
|
99
|
+
|
100
|
+
image_hash = element_to_hash(image_element, %w[width height])
|
101
|
+
hash[:image] = image_hash[:source] if image_hash.has_key?(:source)
|
102
|
+
hash[:imagewidth] = image_hash[:width ] if image_hash.has_key?(:width )
|
103
|
+
hash[:imageheight] = image_hash[:height] if image_hash.has_key?(:height)
|
104
|
+
hash[:transparentcolor] = image_hash[:trans ] if image_hash.has_key?(:trans )
|
105
|
+
|
106
|
+
hash
|
107
|
+
end
|
108
|
+
|
109
|
+
def objectgroup_to_hash(objectgroup_element)
|
110
|
+
objectgroup_hash = element_to_hash(objectgroup_element,
|
111
|
+
%w[x y width height offsetx offsety],
|
112
|
+
%w[opacity],
|
113
|
+
%w[visible]
|
114
|
+
)
|
115
|
+
objectgroup_hash.merge!(properties_parent_to_hash(objectgroup_element))
|
116
|
+
objectgroup_hash[:objects] = []
|
117
|
+
objectgroup_element.each_element("object") do |object_element|
|
118
|
+
objectgroup_hash[:objects].push(object_to_hash(object_element))
|
119
|
+
end
|
120
|
+
|
121
|
+
objectgroup_hash
|
122
|
+
end
|
123
|
+
|
124
|
+
def object_to_hash(object_element)
|
125
|
+
object_hash = { rotation: 0, visible: true }
|
126
|
+
|
127
|
+
object_hash.merge!(element_to_hash(object_element,
|
128
|
+
%w[id gid],
|
129
|
+
%w[x y width height rotation opacity],
|
130
|
+
%w[visible]
|
131
|
+
))
|
132
|
+
object_hash.merge!(properties_parent_to_hash(object_element))
|
133
|
+
object_hash[:ellipse] = true unless object_element.get_elements("ellipse").empty?
|
134
|
+
object_hash[:point] = true unless object_element.get_elements("point").empty?
|
135
|
+
object_element.each_element("polygon") do |polygon_element|
|
136
|
+
object_hash[:polygon] = polygon_element.attribute("points").to_s.split(" ").map do |point|
|
137
|
+
x, y = point.split(",").map(&:to_f)
|
138
|
+
{ x: x, y: y }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
object_element.each_element("polyline") do |polyline_element|
|
142
|
+
object_hash[:polyline] = polyline_element.attribute("points").to_s.split(" ").map do |point|
|
143
|
+
x, y = point.split(",").map(&:to_f)
|
144
|
+
{ x: x, y: y }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
object_element.each_element("text") do |text_element|
|
148
|
+
object_hash[:text] = element_to_hash(text_element,
|
149
|
+
%w[pixelsize],
|
150
|
+
%w[],
|
151
|
+
%w[wrap bold italic underline strikeout kerning]
|
152
|
+
)
|
153
|
+
object_hash[:text][:text] = text_element.text
|
154
|
+
end
|
155
|
+
|
156
|
+
object_hash
|
157
|
+
end
|
158
|
+
|
159
|
+
def animation_to_array(animation_element)
|
160
|
+
animations = []
|
161
|
+
|
162
|
+
animation_element.each_element("frame") do |frame|
|
163
|
+
animations.push({
|
164
|
+
tileid: frame.attribute("tileid" ).to_s.to_i,
|
165
|
+
duration: frame.attribute("duration").to_s.to_i
|
166
|
+
})
|
167
|
+
end
|
168
|
+
|
169
|
+
animations
|
170
|
+
end
|
171
|
+
|
172
|
+
def layers_to_array(layers_parent_element)
|
173
|
+
layers_array = []
|
174
|
+
|
175
|
+
layers_parent_element.each_child do |layer_element|
|
176
|
+
next unless layer_element.is_a?(REXML::Element)
|
177
|
+
layer_hash = element_to_hash(layer_element,
|
178
|
+
%w[x y width height offsetx offsety],
|
179
|
+
%w[opacity],
|
180
|
+
%w[visible]
|
181
|
+
)
|
182
|
+
layer_hash.merge!(properties_parent_to_hash(layer_element))
|
183
|
+
|
184
|
+
case layer_element.name.to_s
|
185
|
+
when "layer"
|
186
|
+
layer_hash[:type] = "tilelayer"
|
187
|
+
data = layer_element.get_elements("data").first
|
188
|
+
data_hash = element_to_hash(data)
|
189
|
+
layer_hash[:compression] = data_hash[:compression] if data_hash.has_key?(:compression)
|
190
|
+
layer_hash[:encoding ] = data_hash[:encoding ] if data_hash.has_key?(:encoding )
|
191
|
+
chunks = data.get_elements("chunk")
|
192
|
+
if chunks.empty?
|
193
|
+
if layer_hash[:encoding] == "csv"
|
194
|
+
layer_hash[:data] = data.text.strip.split(",").map(&:to_i)
|
195
|
+
else
|
196
|
+
layer_hash[:data] = data.text
|
197
|
+
end
|
198
|
+
else
|
199
|
+
layer_hash[:chunks] = []
|
200
|
+
chunks.each do |chunk|
|
201
|
+
chunk_hash = element_to_hash(chunk, %w[x y width height])
|
202
|
+
if layer_hash[:encoding] == "csv"
|
203
|
+
chunk_hash[:data] = chunk.text.strip.split(",").map(&:to_i)
|
204
|
+
else
|
205
|
+
chunk_hash[:data] = chunk.text
|
206
|
+
end
|
207
|
+
layer_hash[:chunks].push(chunk_hash)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
when "objectgroup"
|
211
|
+
layer_hash[:type] = "objectgroup"
|
212
|
+
layer_hash.merge!(objectgroup_to_hash(layer_element))
|
213
|
+
when "imagelayer"
|
214
|
+
layer_hash[:type] = "imagelayer"
|
215
|
+
layer_element.each_element("image") do |image_element|
|
216
|
+
layer_hash.merge!(image_to_hash(image_element))
|
217
|
+
end
|
218
|
+
when "group"
|
219
|
+
layer_hash[:type] = "group"
|
220
|
+
layer_hash[:layers] = layers_to_array(layer_element)
|
221
|
+
else
|
222
|
+
next
|
223
|
+
end
|
224
|
+
layers_array.push(layer_hash)
|
225
|
+
end
|
226
|
+
|
227
|
+
layers_array
|
228
|
+
end
|
229
|
+
|
230
|
+
def tmx_to_hash(tmx)
|
231
|
+
map_element = tmx.root
|
232
|
+
hash = element_to_hash(map_element,
|
233
|
+
%w[width height tilewidth tileheight hexsidelength nextobjectid],
|
234
|
+
%w[version],
|
235
|
+
%w[]
|
236
|
+
)
|
237
|
+
hash.merge!(properties_parent_to_hash(map_element))
|
238
|
+
hash[:tilesets] = []
|
239
|
+
map_element.each_element("tileset") do |tileset_element|
|
240
|
+
hash[:tilesets].push(tileset_to_hash(tileset_element))
|
241
|
+
end
|
242
|
+
hash[:layers] = layers_to_array(map_element)
|
243
|
+
|
244
|
+
hash
|
245
|
+
end
|
246
|
+
|
247
|
+
def tsx_to_hash(tsx)
|
248
|
+
hash = tileset_to_hash(tsx.root)
|
249
|
+
|
250
|
+
hash
|
251
|
+
end
|
252
|
+
|
253
|
+
def tx_to_hash(tx)
|
254
|
+
hash = {}
|
255
|
+
|
256
|
+
tx.root.each_element("tileset") do |tileset_element|
|
257
|
+
hash[:tileset] = element_to_hash(tileset_element,
|
258
|
+
%w[firstgid],
|
259
|
+
%w[],
|
260
|
+
%w[]
|
261
|
+
)
|
262
|
+
end
|
263
|
+
tx.root.each_element("object") do |object_element|
|
264
|
+
hash[:object] = object_to_hash(object_element)
|
265
|
+
end
|
266
|
+
|
267
|
+
hash
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|