tmx 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|