Tileset! I've got an RMXP implementation for you right here. Well...it will probably take some modification, because the viewport code uses other systems I wrote and it is designed for GOSU rather than plain OpenGL. You probably don't want to split the images into individual textures like this, you want to load it as one texture (if you can) and draw with UVs. But you can do this I think. The only part that needs explaining is that `Gosu::Image.load_tiles` creates an array of textures, in this case all 32x32 pixel tiles, row-by-row (so the first row would be tiles 0-7, the next 8-15, etc).
Every time I come back to this I am again disappointed that I did not do the GL calls myself in this way. Oh well. This should help you get started though.
[rgss]# RMXP Tilemap (gosu)
#
# Readable/Writable Attributes :
# - viewport : Viewport used for sprites
# - map_data : 3D Table of Tile ID Data
# - flash_data : 3D Table of Tile Color Data
# - priorities : 3D Table of Tile Priorities
# - ox, oy : Tilemap layer offsets
# - zoom : Zoom value as fraction
# - tilesize : Zoom value as size of individual tile (normal is 32.0)
# - visible : Tilemap Visible Flag
# - is_a_plane : Behaves like a Plane (loops around edges)
# - tileset : Name of Bitmap
# - autotiles : Array of Autotile Filenames
class Tilemap
include Disposable
VP = 2 # Number of tiles beyond viewport to refresh
FA = 64 # Alpha value of the color of flash data
Autotile_Speed = 20 # Number of frames between autotile animations
Autotiles = [
[416,432,512,528], [ 64,432,512,528], [416, 80,512,528], [ 64, 80,512,528],
[416,432,512,176], [ 64,432,512,176], [416, 80,512,176], [ 64, 80,512,176],
[416,432,160,528], [ 64,432,160,528], [416, 80,160,528], [ 64, 80,160,528],
[416,432,160,176], [ 64,432,160,176], [416, 80,160,176], [ 64, 80,160,176],
[384,400,480,496], [384, 80,480,496], [384,400,480,176], [384, 80,480,176],
[224,240,320,336], [224,240,320,176], [224,240,160,336], [224,240,160,176],
[448,464,544,560], [448,464,160,560], [ 64,464,544,560], [ 64,464,160,560],
[608,624,704,720], [ 64,624,704,720], [608, 80,704,720], [ 64, 80,704,720],
[384,464,480,560], [224,240,704,720], [192,208,288,304], [192,208,288,176],
[256,272,352,368], [256,272,160,368], [640,656,736,752], [ 64,656,736,752],
[576,592,672,688], [576, 80,672,688], [192,272,288,368], [192,208,672,688],
[576,656,672,752], [256,272,736,752], [192,272,672,752], [ 0, 16, 96,112]
]
DEFAULTS = {:tileset => nil, :autotiles => [], :map_data => nil,
:flash_data => nil, :priorities => nil, :visible => true,
x => 0,
y => 0, :zoom => 1.0, :is_a_plane => true,
:manager => nil}
# Public Instance Variables
attr_reader :gosuwindow # Instance of Gosu::Window it's drawing to
attr_reader :tileset # Tileset Image
attr_reader :autotiles # Array of Autotile Images
attr_accessor :map_data # 3D Table of Tile Settings
attr_reader :flash_data # 3D Table of Sprite Flash Colors
attr_accessor :priorities # 3D Table of Tileset Priorities
attr_accessor :visible # Tilemap Visibility
attr_accessor
x # Bitmap Offsets
attr_accessor
y # Bitmap Offsets
attr_accessor :zoom # Zoom Fraction
attr_accessor :is_a_plane # Loops around edges
# Object Initialization
def initialize(manager = nil, opts = {})
@gosuwindow = $GameWindow
DEFAULTS.merge!(opts).each do |sym, val|
instance_variable_set("@#{sym}", val)
end
@manager = manager unless manager.nil?
@autotiles_cache = @autotiles
self.flash_data = @flash_data
@tiles = []
@frame = 0
(@manager.nil? ? @gosuwindow.draw_manager : @manager).manage(self)
end
# Get "viewport"
def viewport
@manager
end
# Set "viewport"
def viewport=(manager)
(@manager.nil? ? @gosuwindow.draw_manager : @manager).unmanage(self)
(manager.nil? ? @gosuwindow.draw_manager : manager).manage(self)
@manager = manager
end
# Get Tile Size
def tilesize
(zoom * 32).to_i
end
# Set Tile Size
def tilesize=(tilesize)
self.zoom = tilesize / 32.0
end
# Set tileset graphic. Recaches the internal tileset.
def tileset=(tileset)
@tiles[384..-1] = Gosu::Image.load_tiles(@gosuwindow, tileset, 32, 32, true)
@tileset = tileset
end
# Set list of autotiles. Recaches the internal tileset.
def autotiles=(autotiles)
autotiles.each_with_index do |autotile, i|
Autotiles.each_with_index do |tiles, j|
key = (i + 1) * 48 + j
@tiles[key] = []
# Draws Auto-Tile Rects
for f in 0..(autotile.width / 96)
bmp = Gosu::Image.new(@gosuwindow,
TexPlay::EmptyImageStub.new(32, 32), true)
tiles.each_with_index do |pos, k|
opts = {:crop => [x1 = pos%96+f*96, x2=pos / 96, x1 + 16, x2 + 16]}
bmp.splice(k % 2 * 16, k / 2 * 16, autotile, opts)
end
@tiles[key][f] = bmp
end
end
end
@autotiles = @autotiles_cache = autotiles
end
# Set flash data. For speed we maintain a separate list of GOSU::Color
# object for actual display.
def flash_data=(flash_data)
@flash_data = flash_data
if flash_data.nil?
@flash_data_colors = nil
else
@flash_data_colors = Hash.new
for y in 0...flash_data.ysize
for x in 0...flash_data.xsize
hex = @flash_data[x, y]
@flash_data_colors[[x, y]] =
Gosu::Color.rgba((hex<<8)*16, ((hex<<4)%16)*16, (hex%16)*16, FA))
end
end
end
end
# Dispose
def dispose
@visible = false
super
end
# Update autotile animation
def update
@frame += 1
end
# Per-frame draw function
def draw
return if @map_data.nil? or @priorities.nil? or !@visible
self.autotiles = @autotiles if @autotiles != @autotiles_cache
ts = tilesize
frame = @frame / Autotile_Speed
xmax = (((@viewport.nil? ? @gosuwindow : @viewport.rect).width + @ox) / ts)
ymax = (((@viewport.nil? ? @gosuwindow : @viewport.rect).height + @oy) / ts)
ydts = @oy / ts
yrange = ydts - VP...ymax + VP
xrange = (@ox / ts) - VP...xmax + VP
for y in yrange
ytop = y - ydts
if y < 0 or y >= @map_data.ysize
next unless @is_a_plane
y %= @map_data.ysize
y += @map_data.ysize if y < 0
end
draw_y = y * ts - @oy
for x in xrange
if x < 0 or x >= @map_data.xsize
next unless @is_a_plane
x %= @map_data.xsize
x += @map_data.xsize if x < 0
end
draw_x = x * ts - @ox
for layer in 0...@map_data.zsize
id = @map_data[x, y, layer]
next if id == 0
z = (ytop + z) * 32 + 64 unless (z = @priorities[id]) == 0
tile = @tiles[id]
tile = @tiles[id][frame % tile.size] if tile.is_a?(Array)
tile.draw(draw_x, draw_y, z, @zoom, @zoom)
end
unless @flash_data.nil?
c = @flash_data_colors[[x, y]]
@gosuwindow.draw_quad(draw_x, draw_y, c, draw_x+ts, draw_y, c,
draw_x, draw_y+ts, c, draw_x+ts, draw_y+ts, c)
end
end # for x
end # for y
end
end
[/rgss]