Oh, I missed your answer. Thanks a lot. I ended with something pretty similar, but decided to stay with pyglet (kept the code though. Maybe I'll have to switch to rabbyt).
On Saturday, July 27, 2013 6:47:23 PM UTC+2, Ryexander wrote: > > 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.
