Files
i-mic-rts/lib/tiled_map.rb

144 lines
3.6 KiB
Ruby

class IMICRTS
class TiledMap
attr_reader :width, :height, :tile_size
attr_reader :layers, :tilesets, :spawnpoints
def initialize(map_file)
@xml = Nokogiri::XML(File.read("#{IMICRTS::ASSETS_PATH}/#{map_file}"))
@width, @height = 0, 0
@tile_size = 32
@layers = []
@tilesets = []
@spawnpoints = []
@tiles = []
parse
terrain = @layers.find { |layer| layer.name.downcase == "terrain" }
@width, @height = terrain.width, terrain.height
@tilesets.each do |tileset|
@tiles.push(*tileset.tiles)
end
@xml = nil
end
def parse
@xml.search("//tileset").each do |tileset|
@tilesets << TileSet.new(tileset)
end
@xml.search("//layer").each do |layer|
@layers << Layer.new(layer)
end
@xml.search("//objectgroup").each do |objectgroup|
if objectgroup.attr("name") == "spawns"
objectgroup.children.each do |object|
next unless object.attr("name") && object.attr("name").downcase.strip == "spawn"
@spawnpoints << SpawnPoint.new(object)
end
end
end
end
def get_tile(tile_id)
return nil if tile_id < 0
@tiles.dig(tile_id)
end
class Layer
attr_reader :name, :width, :height
def initialize(xml_layer)
@name = xml_layer["name"]
@width, @height = Integer(xml_layer["width"]), Integer(xml_layer["height"])
@data = []
xml_layer.css("data").inner_html.each_line do |line|
@data.push(*line.strip.split(",").map { |id| Integer(id) })
end
end
def data(x, y)
@data[x + y * @width]
end
end
class TileSet
attr_reader :first_gid, :name, :tile_width, :tile_height, :tile_count, :columns, :rows
attr_reader :tiles
Tile = Struct.new(:image, :data)
def initialize(xml_tileset)
@first_gid = nil
@tiles = []
xml_tileset.attributes.each do |name, attrib|
case name
when "firstgid"
@first_gid = Integer(attrib.value)
when "source"
parse(attrib.value)
end
end
end
def parse(file)
xml = Nokogiri::XML(File.read("#{IMICRTS::ASSETS_PATH}/#{file.sub("../", "")}"))
tileset = xml.search("//tileset").first
data = {}
tileset.attributes.each { |attrib, value| data[attrib] = value.value }
data.each do |key, value|
case key
when "name"
@name = value
when "tilewidth"
@tile_width = Integer(value)
when "tileheight"
@tile_height = Integer(value)
when "tilecount"
@tile_count = Integer(value)
when "columns"
@columns = Integer(value)
when "rows"
@rows = Integer(value)
end
end
path = tileset.search("//image").first.attributes.detect { |a, v| a == "source" }.last.value
images = Gosu::Image.load_tiles("#{IMICRTS::ASSETS_PATH}/tilesets/#{path}", @tile_width, @tile_height, retro: true)
tileset.search("//tile").each_with_index do |xml, index|
tile = Tile.new
tile.image = images[index]
tile.data = FriendlyHash.new
xml.attributes.each do |name, data|
tile.data[name.to_sym] = data.value if name == "type"
end
@tiles << tile
end
end
end
class SpawnPoint
attr_reader :x, :y
def initialize(xml_object)
@x, @y = Integer(xml_object.attr("x")), Integer(xml_object.attr("y"))
end
end
end
end