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.


Reply via email to