tmx 0.0.1 → 0.1.0
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/.gitignore +15 -10
- data/.rspec +2 -0
- data/Gemfile +8 -2
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/lib/tmx.rb +52 -13
- data/lib/tmx/layer.rb +4 -73
- data/lib/tmx/map.rb +11 -143
- data/lib/tmx/parsers/json.rb +24 -0
- data/lib/tmx/parsers/parsers.rb +30 -0
- data/lib/tmx/parsers/tmx.rb +145 -0
- data/lib/tmx/parsers/unknown.rb +24 -0
- data/lib/tmx/tile_set.rb +4 -34
- data/lib/tmx/version.rb +1 -1
- data/spec/features/json_format_spec.rb +76 -0
- data/spec/features/xml_format_spec.rb +84 -0
- data/spec/fixtures/map.json +39 -0
- data/spec/fixtures/map_csv.tmx +25 -0
- data/spec/fixtures/map_gzip.tmx +14 -0
- data/spec/fixtures/map_uncompressed.tmx +14 -0
- data/spec/fixtures/map_xml.tmx +205 -0
- data/spec/fixtures/map_zlib.tmx +17 -0
- data/spec/spec_helper.rb +16 -49
- data/tmx.gemspec +18 -22
- metadata +54 -70
- data/README.markdown +0 -92
- data/Rakefile +0 -11
- data/data/door.png +0 -0
- data/data/dude.png +0 -0
- data/data/test-tiles.png +0 -0
- data/data/test.tmx +0 -62
- data/examples/example-chingu.rb +0 -114
- data/lib/tmx/coder.rb +0 -39
- data/lib/tmx/coder/base64.rb +0 -13
- data/lib/tmx/coder/gzip.rb +0 -21
- data/lib/tmx/map/tile_cache.rb +0 -83
- data/lib/tmx/map/xml_loader.rb +0 -41
- data/lib/tmx/nokogiri_additions.rb +0 -56
- data/lib/tmx/object_group.rb +0 -30
- data/spec/coder_spec.rb +0 -29
- data/spec/map_spec.rb +0 -50
- data/spec/nokogiri_spec.rb +0 -5
- data/spec/object_group_spec.rb +0 -41
data/README.markdown
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
# README
|
2
|
-
## WHAT IS THIS
|
3
|
-
|
4
|
-
Eventually, a usable TMX map loader that works with Gosu and doesn't care
|
5
|
-
whether you're using Chingu or some home-grown game engine of your own
|
6
|
-
devising.
|
7
|
-
|
8
|
-
### WHY ON EARTH
|
9
|
-
|
10
|
-
I like Chingu and a TMX loader already exists for it, but it's just not the
|
11
|
-
right tool for what I want to do. Hopefully others will find this useful as
|
12
|
-
well. :)
|
13
|
-
|
14
|
-
### WHAT IS MISSING
|
15
|
-
|
16
|
-
Here's what's not: so far, map data is loaded and layers, object groups and
|
17
|
-
tile sets are created.
|
18
|
-
|
19
|
-
Validating the XML document to its DTD would be nice too, but I'll be buggered
|
20
|
-
if I can get Nokogiri to actually load the DTD. There is inadequate or no
|
21
|
-
documentation on this topic. Probably we'll just have mysterious failures on
|
22
|
-
unsupported or erroneous TMX files, which is not ideal.
|
23
|
-
|
24
|
-
Possible consideration for the future: move the dependency on Gosu into a
|
25
|
-
separate, mixable, matchable module. Maybe add explicit Chingu support too.
|
26
|
-
Handle tile set creation and drawing ops the same way we do object creation:
|
27
|
-
define a callback hook and let the user take care of it. Awesome.
|
28
|
-
|
29
|
-
Help is welcome, obviously.
|
30
|
-
|
31
|
-
## INSTALL
|
32
|
-
|
33
|
-
Don't do it yet. The API is so unstable it does not have a half life but a
|
34
|
-
quarter life.
|
35
|
-
|
36
|
-
### PREREQUISITES
|
37
|
-
|
38
|
-
* ruby >= 1.9.1 (probably)
|
39
|
-
* nokogiri
|
40
|
-
|
41
|
-
## LICENSE
|
42
|
-
|
43
|
-
This software is available under the terms of the MIT license for no better
|
44
|
-
reason than that this is the license of Gosu itself. This means that you are
|
45
|
-
technically allowed to use my hard work as part of your proprietary,
|
46
|
-
commercial product with no obligation to give anything back but credit where
|
47
|
-
it's due. Use your discretion on that one.
|
48
|
-
|
49
|
-
The full license is reproduced here for posterity:
|
50
|
-
|
51
|
-
> Copyright © 2009–2010 Eris
|
52
|
-
>
|
53
|
-
> Permission is hereby granted, free of charge, to any person
|
54
|
-
> obtaining a copy of this software and associated documentation
|
55
|
-
> files (the "Software"), to deal in the Software without
|
56
|
-
> restriction, including without limitation the rights to use,
|
57
|
-
> copy, modify, merge, publish, distribute, sublicense, and/or sell
|
58
|
-
> copies of the Software, and to permit persons to whom the
|
59
|
-
> Software is furnished to do so, subject to the following
|
60
|
-
> conditions:
|
61
|
-
>
|
62
|
-
> The above copyright notice and this permission notice shall be
|
63
|
-
> included in all copies or substantial portions of the Software.
|
64
|
-
>
|
65
|
-
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
66
|
-
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
67
|
-
> OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
68
|
-
> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
69
|
-
> HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
70
|
-
> WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
71
|
-
> FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
72
|
-
> OTHER DEALINGS IN THE SOFTWARE.
|
73
|
-
|
74
|
-
## AUTHORS
|
75
|
-
|
76
|
-
* Eris <eris.discord@gmail.com>
|
77
|
-
* your name here!
|
78
|
-
|
79
|
-
## SEE ALSO
|
80
|
-
|
81
|
-
* [Gosu][], a 2D game development library for Ruby and C++
|
82
|
-
* [Chingu][], a higher level game library built on top of Gosu
|
83
|
-
* [Chipmunk][], a 2D rigid body physics engine in C
|
84
|
-
* [chipmunk-ffi][], more up-to-date Ruby bindings for Chipmunk
|
85
|
-
* [Tiled][], a flexible tile map editor and the origin of the TMX format (I
|
86
|
-
think).
|
87
|
-
|
88
|
-
[chingu]: http://github.com/ippa/chingu
|
89
|
-
[chipmunk]: http://code.google.com/p/chipmunk-physics
|
90
|
-
[chipmunk-ffi]: http://github.com/shawn42/chipmunk-ffi
|
91
|
-
[gosu]: http://libgosu.org
|
92
|
-
[tiled]: http://mapeditor.org/
|
data/Rakefile
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'rspec/core/rake_task'
|
2
|
-
require "bundler/gem_tasks"
|
3
|
-
|
4
|
-
desc 'Default: run specs.'
|
5
|
-
task :default => :spec
|
6
|
-
|
7
|
-
desc "Run specs"
|
8
|
-
RSpec::Core::RakeTask.new do |t|
|
9
|
-
# t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
10
|
-
# Put spec opts in a file named .rspec in root
|
11
|
-
end
|
data/data/door.png
DELETED
Binary file
|
data/data/dude.png
DELETED
Binary file
|
data/data/test-tiles.png
DELETED
Binary file
|
data/data/test.tmx
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<map version="1.0" orientation="orthogonal" width="16" height="16" tilewidth="16" tileheight="16">
|
3
|
-
<properties>
|
4
|
-
<property name="bg1" value="#402010"/>
|
5
|
-
<property name="bg2" value="#100000"/>
|
6
|
-
<property name="fg1" value="#00ff0000"/>
|
7
|
-
<property name="fg2" value="#10ff0000"/>
|
8
|
-
<property name="display_name" value="Test Map"/>
|
9
|
-
</properties>
|
10
|
-
<tileset firstgid="1" name="debug" tilewidth="16" tileheight="16">
|
11
|
-
<image source="test-tiles.png"/>
|
12
|
-
</tileset>
|
13
|
-
<layer name="background" width="16" height="16" opacity="0.75">
|
14
|
-
<data encoding="base64" compression="gzip">
|
15
|
-
H4sIAAAAAAAAA2NgGAXogInK5rGh0aNgFAwWAADxvIrYAAQAAA==
|
16
|
-
</data>
|
17
|
-
</layer>
|
18
|
-
<layer name="obstacle" width="16" height="16">
|
19
|
-
<data encoding="base64" compression="gzip">
|
20
|
-
H4sIAAAAAAAAA82T4QqAIAyEZ1Jakb3/27YjB2MMMfvjwSHMfTp1BiIqg47sTOPKk/EXvWeCAnupLmqMDR7aa95RnVQumfye+vV6GM+PfEtgV/b9g5/p/UR4u+jEe3ncSTIx9Ia9J4/H3pvDezUmwwvbw0uN0h+658Stv4t59NIDVh+CwAAEAAA=
|
21
|
-
</data>
|
22
|
-
</layer>
|
23
|
-
<objectgroup name="doors" width="16" height="16">
|
24
|
-
<object name="door1" type="Door" x="128" y="208" width="16" height="32">
|
25
|
-
<properties>
|
26
|
-
<property name="image" value="door.png"/>
|
27
|
-
<property name="target" value="door2"/>
|
28
|
-
</properties>
|
29
|
-
</object>
|
30
|
-
<object name="door2" type="Door" x="64" y="32" width="16" height="32">
|
31
|
-
<properties>
|
32
|
-
<property name="image" value="door.png"/>
|
33
|
-
<property name="target" value="door1"/>
|
34
|
-
</properties>
|
35
|
-
</object>
|
36
|
-
</objectgroup>
|
37
|
-
<objectgroup name="objects" width="16" height="16">
|
38
|
-
<properties>
|
39
|
-
<property name="what_is_this" value="it's boxes ok"/>
|
40
|
-
</properties>
|
41
|
-
<object name="cardboard_box" type="Box" x="160" y="160" width="32" height="32">
|
42
|
-
<properties>
|
43
|
-
<property name="image" value="tid:16"/>
|
44
|
-
</properties>
|
45
|
-
</object>
|
46
|
-
<object name="stone_block" type="Box" x="192" y="32" width="32" height="32">
|
47
|
-
<properties>
|
48
|
-
<property name="image" value="tid:16"/>
|
49
|
-
</properties>
|
50
|
-
</object>
|
51
|
-
<object name="dude" type="Dude" x="80" y="144" width="16" height="32">
|
52
|
-
<properties>
|
53
|
-
<property name="image" value="dude.png"/>
|
54
|
-
</properties>
|
55
|
-
</object>
|
56
|
-
</objectgroup>
|
57
|
-
<layer name="foreground" width="16" height="16" opacity="0.75">
|
58
|
-
<data encoding="base64" compression="gzip">
|
59
|
-
H4sIAAAAAAAAA2NgGAWjYPABRiBmIoAJATYCeCD1EwMo1U8MAADF4i9MAAQAAA==
|
60
|
-
</data>
|
61
|
-
</layer>
|
62
|
-
</map>
|
data/examples/example-chingu.rb
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
require 'chingu'
|
2
|
-
require 'tmx'
|
3
|
-
require 'opengl' # Chingu needs it for retrofy
|
4
|
-
|
5
|
-
class Float
|
6
|
-
INFINITY = 1.0 / 0.0 unless const_defined? :INFINITY
|
7
|
-
end
|
8
|
-
|
9
|
-
class Box < Chingu::GameObject
|
10
|
-
# "It's just a box."
|
11
|
-
|
12
|
-
# (Chingu takes care of everything we need here (it's magic))
|
13
|
-
end
|
14
|
-
|
15
|
-
class Door < Chingu::GameObject
|
16
|
-
# this ought to take you somewhere else
|
17
|
-
end
|
18
|
-
|
19
|
-
class Dude < Chingu::GameObject
|
20
|
-
# maybe your player logic goes here
|
21
|
-
end
|
22
|
-
|
23
|
-
class MapState < Chingu::GameState
|
24
|
-
has_trait :viewport
|
25
|
-
|
26
|
-
def initialize map_name, *rest
|
27
|
-
super *rest
|
28
|
-
|
29
|
-
# load our map
|
30
|
-
@map = TMX::Map.new $window, map_name,
|
31
|
-
:on_object => method(:create_chingu_object)
|
32
|
-
@banner = Gosu::Image.from_text $window,
|
33
|
-
@map.properties[:display_name],
|
34
|
-
'Helvetica', 24
|
35
|
-
|
36
|
-
$window.caption = 'tmx demo - %s' % @map.properties[:display_name]
|
37
|
-
end
|
38
|
-
|
39
|
-
def create_chingu_object name, group, properties
|
40
|
-
map = group.map
|
41
|
-
obj_class = Kernel.const_get properties[:type] rescue nil
|
42
|
-
|
43
|
-
# assert that the object is a valid type
|
44
|
-
raise TypeError, "#{properties[:type]} is not a game object" \
|
45
|
-
unless obj_class.is_a? Class \
|
46
|
-
and obj_class.ancestors.include? Chingu::BasicGameObject
|
47
|
-
|
48
|
-
# load image
|
49
|
-
image_name = properties[:image]
|
50
|
-
image = case image_name
|
51
|
-
when /^tid:(\d+)$/
|
52
|
-
# a tile from the map's tile set
|
53
|
-
map.tile_set[Integer($1)]
|
54
|
-
when nil
|
55
|
-
# default image
|
56
|
-
Gosu::Image['default']
|
57
|
-
else
|
58
|
-
# image as named
|
59
|
-
Gosu::Image[File.join 'data', image_name]
|
60
|
-
end
|
61
|
-
|
62
|
-
# convert TMX properties to what Chingu is expecting
|
63
|
-
properties.merge! \
|
64
|
-
:image => image.retrofy,
|
65
|
-
:x => properties[:x] + properties[:width] / 2,
|
66
|
-
:y => properties[:y] + properties[:height] / 2,
|
67
|
-
:factor_x => properties[:width].to_f / image.width,
|
68
|
-
:factor_y => properties[:height].to_f / image.height,
|
69
|
-
:zorder => 1
|
70
|
-
|
71
|
-
# create and return the game object
|
72
|
-
obj_class.create properties
|
73
|
-
end
|
74
|
-
|
75
|
-
def update
|
76
|
-
super
|
77
|
-
# move the map opposite the mouse pointer, with lag
|
78
|
-
viewport.x = 0.9 * viewport.x + 0.1 * ($window.mouse_x - $window.width + @map.width / 2)
|
79
|
-
viewport.y = 0.9 * viewport.y + 0.1 * ($window.mouse_y - $window.height + @map.height / 2)
|
80
|
-
end
|
81
|
-
|
82
|
-
def draw
|
83
|
-
super
|
84
|
-
|
85
|
-
fill_gradient \
|
86
|
-
:from => @map.properties[:bg1],
|
87
|
-
:to => @map.properties[:bg2],
|
88
|
-
:zorder => -Float::INFINITY
|
89
|
-
|
90
|
-
# map is not a game object
|
91
|
-
@map.draw -viewport.x, -viewport.y
|
92
|
-
|
93
|
-
fill_gradient \
|
94
|
-
:from => @map.properties[:fg1],
|
95
|
-
:to => @map.properties[:fg2],
|
96
|
-
:zorder => Float::INFINITY
|
97
|
-
|
98
|
-
@banner.draw 8, 8, Float::INFINITY
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
class MapWindow < Chingu::Window
|
103
|
-
def initialize
|
104
|
-
super 400, 200, false
|
105
|
-
|
106
|
-
# global inputs for our demo
|
107
|
-
self.input = { :escape => :close }
|
108
|
-
|
109
|
-
# load that map
|
110
|
-
push_game_state MapState.new('data/test.tmx')
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
MapWindow.new.show
|
data/lib/tmx/coder.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
module Tmx
|
2
|
-
module Coder
|
3
|
-
# default coders
|
4
|
-
autoload :Base64, 'tmx/coder/base64'
|
5
|
-
autoload :Gzip, 'tmx/coder/gzip'
|
6
|
-
|
7
|
-
def self.encode str, *encodings
|
8
|
-
encodings.reject(&:nil?).reduce(str) do |data, encoding|
|
9
|
-
find_coder(encoding).encode(data)
|
10
|
-
end
|
11
|
-
end # encode
|
12
|
-
|
13
|
-
def self.decode str, *encodings
|
14
|
-
encodings.reject(&:nil?).reverse.reduce(str) do |data, encoding|
|
15
|
-
find_coder(encoding).decode(data)
|
16
|
-
end
|
17
|
-
end # decode
|
18
|
-
|
19
|
-
def self.find_coder name
|
20
|
-
const_name = name.to_s.capitalize.gsub /(?:\b|_)([a-z])/, &:upcase
|
21
|
-
if const_defined? const_name
|
22
|
-
const_get const_name
|
23
|
-
else
|
24
|
-
raise NameError, "unknown coder #{name}"
|
25
|
-
end
|
26
|
-
end # find_coder
|
27
|
-
|
28
|
-
def self.register_coder name, mod
|
29
|
-
const_name = name.to_s.capitalize.gsub /(?:\b|_)([a-z])/, &:upcase
|
30
|
-
if not const_defined? const_name
|
31
|
-
const_set const_name, mod
|
32
|
-
else
|
33
|
-
raise NameError, "coder #{name} already registered"
|
34
|
-
end
|
35
|
-
end # register_coder
|
36
|
-
|
37
|
-
end # Coder
|
38
|
-
|
39
|
-
end
|
data/lib/tmx/coder/base64.rb
DELETED
data/lib/tmx/coder/gzip.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Tmx
|
2
|
-
module Coder
|
3
|
-
module Gzip
|
4
|
-
def self.encode str
|
5
|
-
buffer = String.new
|
6
|
-
writer = Zlib::GzipWriter.new(StringIO.new(buffer))
|
7
|
-
writer << str
|
8
|
-
writer.close
|
9
|
-
buffer
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.decode str
|
13
|
-
reader = Zlib::GzipReader.new(StringIO.new(str))
|
14
|
-
output = reader.read
|
15
|
-
reader.close
|
16
|
-
output
|
17
|
-
end
|
18
|
-
|
19
|
-
end # Gzip
|
20
|
-
end
|
21
|
-
end
|
data/lib/tmx/map/tile_cache.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
module Tmx
|
2
|
-
# WARNING this is currently deprecated and not actually used
|
3
|
-
class Map::TileCache
|
4
|
-
def initialize map
|
5
|
-
@map = WeakRef.new map
|
6
|
-
|
7
|
-
@tile_cache = []
|
8
|
-
@map_cache = []
|
9
|
-
|
10
|
-
@layer_count = 0
|
11
|
-
|
12
|
-
@columns, @rows = 0, 0
|
13
|
-
@tile_width, @tile_height = 0, 0
|
14
|
-
end # initialize
|
15
|
-
|
16
|
-
def rebuild!
|
17
|
-
rebuild_tile_set!
|
18
|
-
rebuild_map!
|
19
|
-
end
|
20
|
-
|
21
|
-
def rebuild_tile_set!
|
22
|
-
raise RuntimeError, "tile set information has been discarded" if @map.tile_sets.nil?
|
23
|
-
|
24
|
-
@tile_cache.clear
|
25
|
-
@map.tile_sets.each_value do |tile_set|
|
26
|
-
@tile_cache[tile_set.range] = tile_set.tiles
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def rebuild_map!
|
31
|
-
raise RuntimeError, "layer information has been discarded" if @map.layers.nil?
|
32
|
-
|
33
|
-
@map_cache.clear
|
34
|
-
|
35
|
-
@layer_count = @map.layers.count
|
36
|
-
|
37
|
-
@columns, @rows = @map.columns, @map.rows
|
38
|
-
@tile_width, @tile_height = @map.tile_width, @map.tile_height
|
39
|
-
|
40
|
-
@map.layers.each_value.with_index do |layer, layer_index|
|
41
|
-
(0...@rows).each do |y|
|
42
|
-
(0...@columns).each do |x|
|
43
|
-
index = _tile_index layer_index, x, y
|
44
|
-
tile_id = layer[x, y]
|
45
|
-
@map_cache[index] = @tile_cache[tile_id]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end # rebuild_map!
|
50
|
-
|
51
|
-
def draw x_off, y_off, z_off, x_range, y_range
|
52
|
-
x_range = [x_range.min, 0].max .. [x_range.max, @columns - 1].min
|
53
|
-
y_range = [y_range.min, 0].max .. [y_range.max, @rows - 1].min
|
54
|
-
|
55
|
-
y_range.each do |y|
|
56
|
-
tile_y_off = y_off + y * @tile_height
|
57
|
-
|
58
|
-
x_range.each do |x|
|
59
|
-
tile_x_off = x_off + x * @tile_width
|
60
|
-
|
61
|
-
range = _tile_range x, y
|
62
|
-
@map_cache[range].each.with_index do |image, z|
|
63
|
-
next if image.nil?
|
64
|
-
image.draw tile_x_off, tile_y_off, z_off + z
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end # draw
|
70
|
-
|
71
|
-
protected
|
72
|
-
|
73
|
-
def _tile_index layer_index, x, y
|
74
|
-
y * @columns * @layer_count + x * @layer_count + layer_index
|
75
|
-
end
|
76
|
-
|
77
|
-
def _tile_range x, y
|
78
|
-
first = _tile_index 0, x, y
|
79
|
-
first...(first + @layer_count)
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
end
|