This is How I did my tile map with rabbty.
ecentialy I have 2 numpy arrays, the first (stored in table) is a 3
dimensional array of the tilemap and it's layers. the only thing the table
array olds in ints that represent an spesfic tile from a tileset. those
ints are turned into actual textures inside the cache (the cache attempts
to generate the texture if it hasn't been requested yet and provide the
same texture ID for every request made for the same tile. the textur are
returned from the cache as pyglet image objects and the get_texture()
method is used to retrieve the texture for rabbyt
the other numpy array is a dtype=object array that is of the same 'shape'
(same size in all 3 dimentions) as the tile table you can ignore the
order='F' part as that is just to maintain comparability with my other code.
you will notice that at first the tilemap is initialized with blank tiles
(self.blank_tile is a empty pyglet image) and then has all the proper
images set in the update method..
my table class is a class built on top of numpy and it's _data attribute
holds the actual numpy array that has a 'F' ordering hence why my sprite
array has teh same ordering. you cna ignore this part and use a strait
numpy array for your table and use default ordering. it wont effect how it
works ore the speed.
the update methods used a third numpy array 'tile_ids' to keep track of
which tile in the tile map has which Id. by finding all the indexes where
this tile_ids array does not match the table and can know each index who'es
textue I need to update.
set_image is mostly unimportant all it does in drop a new rabbyt sprite
with the right texture into the array to set the right tile for the tile
map postilion.
and now we get to the draw method
and it's REALLY simple
all I do is first size the 3 dimensional array that is the tile map to
obtain ONLY the sprites visible on the screen.
next I loop through the z dimention of the tilemap as that holds the layers
of the map.
then for ever z I take the 2 dim array that holds that layer and flatten it
to a one dimensional array. and pass that 1 dim array of visible sprites in
that layer to rabbyt_render_unsorted which is a really fast c loop that
calls render on each sprite.
the result is a render of the tilemap that only includes the visible
sprites. and a REALLY easy to manipulate tilemap
def createTilemap(self):
'''
create the tilemap
'''
shape = self.table.getShape()
sprites = numpy.empty(shape, dtype=object, order='F')
for x in xrange(shape[0]):
for y in xrange(shape[1]):
for z in xrange(shape[2]):
sprites[x, y, z] = self.makeSprite(x, y, z)
return sprites
def makeSprite(self, x, y, z, texture=None):
xpos = x * 32 + 16
ypos = ((self.table.getShape()[1] - y) * 32) - 32 + 16
if texture == None:
texture = self.blank_tile.get_texture()
sprite = rabbyt.Sprite(texture, x=xpos, y=ypos)
return sprite
def update(self):
'''
checks for change in tile ids and updates the tilemap
'''
#if the arn't the same size
if self.tile_ids.shape != self.table.getShape():
self.resize(*self.table.getShape())
#find the tiles who's ids have changed
indexes = numpy.argwhere(self.table._data != self.tile_ids)
#we have the idexes of the tiles we need to update so copy
#the changed data over so we don;t have to update again
self.tile_ids[:] = self.table._data[:]
for index in indexes:
self.set_image(tuple(index), self.tile_ids[tuple(index)])
def set_image(self, index, id):
'''
change the bitmap of a tile (by making a new sprite)
'''
#if for some reason the sprite does not exist (ie. the map was resized)
make it
x, y, z = index
if self.tiles[index] == None:
self.tiles[index] = self.makeSprite(x, y, z)
flag = False
#get the tile bitmap
if id < 384:
if id <= 47:
bitmap = self.blank_tile
else:
#get the filename
autotile = self.autotile_names[int(id) / 48 - 1]
#get the right pattern
pattern = id % 48
#collect the tile form the cache checking the local project
folder
#and the system RTP folder
bitmap = self.cache.AutotilePattern(autotile, pattern)
if not bitmap:
bitmap = self.cache.AutotilePattern(autotile, pattern)
if not bitmap:
flag = True
bitmap = self.blank_tile
#normal tile
else:
#get the tile bitmap
bitmap = self.cache.Tile(self.tileset_name, id, 0)
if not bitmap:
bitmap = self.cache.Tile(self.tileset_name, id, 0)
if not bitmap:
flag = True
bitmap = self.blank_tile
#draw the tile to the surface
self.tiles[index].texture = bitmap.get_texture()
def Draw(self, x, y, width, height):
'''
draw the layers of the map
'''
on_screen = self.tiles[x:x + width, y:y + height]
if not self.LayerDimming or self.activeLayer > on_screen.shape[2]:
#draw the dimlayer first
self.dimmingSprite.render()
for z in xrange(on_screen.shape[2]):
if z == self.activeLayer and self.LayerDimming:
if self.dimmingSprite != None:
self.dimmingSprite.render()
rabbyt.render_unsorted(on_screen[:, :, z].flatten())
if you need further explanation feel free to ask.
On Friday, July 19, 2013 5:07:01 PM UTC-6, Fred wrote:
>
> Hello,
>
> I'm using pyglet to make an old-fashioned 2D RPG engine. A map is made of
> layers (up to 10), each layer is made of tiles (21 * 15 tiles). A map can
> be big (more than 100 x 100 tiles), and sometimes infinite (toric).
>
> The map is rendered in a single batch, each layer is attached to an
> OrderedGroup.
> A tile from a layer is attached to a sprite (in 'static' mode), but I keep
> only tiles that are effectively on screen (in a list). When a tile goes
> outside the screen, the sprite is destroyed (it's removed from the list so
> I suppose it's destroyed since there are no references on it anymore), and
> to the contrary, when a new tile comes inside the screen, I add a new
> sprite to the group. I've read they are slow operations, but I don't see a
> better way (the maps are too big to keep all the sprites).
>
> My problem is that I have performances issues for the biggest maps : I
> reach at most 5 fps, where I'd like to have 60. Event for smaller ones
> (only 3 layers), I get 30 - 40 fps.
>
> Am I doing it the wrong way (and if so, could you please point me better
> ideas) or is my goal clearly unreachable using Python + pyglet, and would
> require C++/OpenGL code ?
>
> Thanks in advance !
>
--
You received this message because you are subscribed to the Google Groups
"pyglet-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/pyglet-users.
For more options, visit https://groups.google.com/groups/opt_out.