Page 1 of 3

Tilemap (Creator-Defined Displayable)

Posted: Thu Nov 05, 2015 5:03 am
by nyaatrap
There are a few tilemap engine in ren'py but I couldn't find simple ones for general use, so I wrote it.
This is a simple creator-defined displayable that creates a tilemap by tiling other displayables.
An example of how to use this displayable will be written on the next post.

Code: Select all

## Tilemap displayable

init -2 python:
    
    class Tilemap(renpy.Displayable):
        
        """
        
        This creates a displayable by tiling other displayables. It has the following field values.
        
        map -  A 2-dimensional list of integers that represent index of a tileset.
        tileset -  A list of displayables that is used as a tile of tilemap.
        tile_width - width of each tile.
        tile_height - height of each tile.
        area - Rectangle area of the displayable that will be rendered. If it's None, default, it renders all tiles. 
                
        """
        
        def __init__(self, map, tileset, tile_width, tile_height, **properties):
            
            super(Tilemap, self).__init__(**properties)            
            self.map = map
            self.tileset = tileset
            self.tile_width = tile_width
            self.tile_height = tile_height                    
            self.area = None                    
            
            
        def render(self, width, height, st, at):
                
            render = renpy.Render(width, height)
            
            # Blit all tiles into the render.
            for y in xrange(len(self.map)):
                for x in xrange(len(self.map[y])):
                    render.blit(renpy.render(self.tileset[self.map[y][x]], self.tile_width, self.tile_height, st, at), (x*self.tile_width, y*self.tile_height))
                    
            # Crop the render.
            if self.area == None:
                render = render.subsurface((0, 0, len(self.map[y])*self.tile_width, len(self.map)*self.tile_height))
            else:
                render = render.subsurface(self.area)
                
            return render
            
            
        def per_interact(self):
            
            # Redraw per interact.
            renpy.redraw(self, 0)
            
            
        def visit(self):
           
           # If the displayable has child displayables, this method should be overridden to return a list of those displayables.
           return self.tileset

Re: Tilemap (Creator-Defined Displayable)

Posted: Thu Nov 05, 2015 5:05 am
by nyaatrap
An example

Code: Select all

init python:
    
    # Define a list of displayables.
    tileset =[Image("water.png"),Image("sand.png"),Image("forest.png"), Image("rock.png")]
        
    # Define a 2-demensional list of integers. Integers should be an index number of a tileset.
    # e.g. 0 stands tileset[0]
    map = [
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
        [0,0,1,1,1,3,3,1,1,1,1,1,1,0,0,0,0],
        [0,1,1,1,1,3,3,3,1,1,1,1,1,1,1,0,0],
        [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1],
        [1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1],
        [1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1],
        [1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1],
        [1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1],
        [1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1],
        [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
        ]
    
    # Create an instance of Tilemap class with following arguments.
    # (map, tileset, tile_width, tile_height).
    tilemap = Tilemap(map, tileset, 64,64)

# Optionally, you can associate it to an image tag
image overworld = tilemap


# The game starts here.
label start:
    
    $ tilemap.area = None
    show overworld at truecenter
    "Showing an entire map"

    $ tilemap.area = (64,64,256,256)
    "Showing only rectangle area of the map"

    return

Re: Tilemap (Creator-Defined Displayable)

Posted: Thu Nov 05, 2015 10:10 am
by firecat
theres a error on your example:

Code: Select all

[code]
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/script.rpy", line 1, in script
    init python:
  File "game/script.rpy", line 27, in <module>
    Tilemap = Tilemap(map, tileset, 64,64)
NameError: name 'Tilemap' is not defined

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/script.rpy", line 1, in script
    init python:
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\ast.py", line 797, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\python.py", line 1448, in py_exec_bytecode
    exec bytecode in globals, locals
  File "game/script.rpy", line 27, in <module>
    Tilemap = Tilemap(map, tileset, 64,64)
NameError: name 'Tilemap' is not defined

Windows-8-6.2.9200
Ren'Py 6.99.6.739
testing1000 0.0
[/code]

Re: Tilemap (Creator-Defined Displayable)

Posted: Thu Nov 05, 2015 10:30 am
by mobychan
@firecat:
just a guess, but did you implement both code parts?

Re: Tilemap (Creator-Defined Displayable)

Posted: Thu Nov 05, 2015 10:54 pm
by firecat
mobychan wrote:@firecat:
just a guess, but did you implement both code parts?
oh i thought they were the same, (one test later) still has bugs. nyaatrap forgot to put character in it but thats not the real problem, its this one.

Code: Select all

[code]
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/script.rpy", line 96, in script
    e "Showing an entire map"
AttributeError: 'str' object has no attribute 'visit_all'

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/script.rpy", line 96, in script
    e "Showing an entire map"
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\ast.py", line 594, in execute
    renpy.exports.say(who, what, interact=self.interact)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\exports.py", line 1032, in say
    who(what, interact=interact)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\character.py", line 826, in __call__
    self.do_display(who, what, cb_args=self.cb_args, **display_args)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\character.py", line 688, in do_display
    **display_args)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\character.py", line 491, in display_say
    rv = renpy.ui.interact(mouse='say', type=type, roll_forward=roll_forward)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\ui.py", line 277, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 2346, in interact
    repeat, rv = self.interact_core(preloads=preloads, **kwargs)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 2602, in interact_core
    root_widget.visit_all(lambda i : i.per_interact())
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 394, in visit_all
    d.visit_all(callback)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 394, in visit_all
    d.visit_all(callback)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 394, in visit_all
    d.visit_all(callback)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 394, in visit_all
    d.visit_all(callback)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 394, in visit_all
    d.visit_all(callback)
  File "C:\Users\angel\Desktop\renpy-6.18.3-sdk\renpy\display\core.py", line 394, in visit_all
    d.visit_all(callback)
AttributeError: 'str' object has no attribute 'visit_all'

Windows-8-6.2.9200
Ren'Py 6.99.6.739
testing1000 0.0
[/code]

Re: Tilemap (Creator-Defined Displayable)

Posted: Fri Nov 06, 2015 12:41 am
by nyaatrap
Fixed the example code. The problem was tileset should be list of displayables for the visit method, but "image_path" isn't a displayable. They should have been written Image("image_path"). If tileset is a list of image path strings not general displayables, you can omit the visit method and no need to use Image() on each tiles.

Re: Tilemap (Creator-Defined Displayable)

Posted: Fri Nov 06, 2015 1:07 am
by trooper6
I made a hex tilemap tester at one point...slightly different than this, but I'll check this out for inspiration as well.

Re: Tilemap (Creator-Defined Displayable)

Posted: Sun Nov 08, 2015 10:44 pm
by nyaatrap
An advanced example that uses a spritesheet and a spreadsheet. With this code, you can import a spreadsheet created by a tool like Tiled Map Editor.

Code: Select all

init -2 python:

    class Spritesheet():
        
        @staticmethod
        def create(file, sprite_width, sprite_height, columns, rows, spacing=0, margin=0):
            
            # This creates a list of displayables from one spritesheet.
            
            list = []
            for j in xrange(rows):
                for i in xrange(columns):
                    list.append(LiveCrop(((sprite_width+spacing)*i+margin, (sprite_height+spacing)*j+margin, sprite_width, sprite_height), file))
                    
            return list
           
            
    class Spreadsheet():
        
        @staticmethod
        def create(file, integer=True):
            
            # This creates a 2-dimentional list from one csv or tsv file.
            # If integer is True, default, strings are converted into integers
        
            map=[]
            f = renpy.file(file)
            for l in f:
                if file.endswith(".csv"):
                    a = l.rstrip().split(",")
                else:
                    a = l.rstrip().split("\t")
                mapline=[]
                for c in a:
                    if integer:
                        c = int(c)
                    mapline.append(c)
                map.append(mapline)
            f.close()
                
            return map

Code: Select all

init python:

    # Define a list of displayables from spritesheet with the following arguments.
    # (file, sprite_width, sprite_height, columns, rows, spacing=0, margin=0)
    tileset = Spritesheet.create("tiles.png", 32, 32, 8, 6, 1, 1)
        
    # Define a 2-demensional list from spreadsheet
    map = Spreadsheet.create("map.csv")
    
    # Create an instance of Tilemap class with following arguments.
    # (map, tileset, tile_width, tile_height).
    
    tilemap = Tilemap(map, tileset, 32, 32)

Re: Tilemap (Creator-Defined Displayable)

Posted: Thu Nov 12, 2015 12:11 pm
by nyaatrap
More advanced demo that allows scrolling a huge map.
Clipboard 1.jpg
tilemap-1.0-all.zip
(26.31 MiB) Downloaded 290 times
This demo uses 500x500 tiles for performance test. It should work even on 5000x5000 tiles, because it only blits surfaces around shown area.
I confirmed it shows displayables fast, and memory usage is low. However, there's one problem - the quality is scrolling is not beautiful. I think it's because of that it uses a simple crop method with no sub-sampling. If someone knows how to make it smoother, let me know.
PS: The demo contains a tileset image from Tiled map editor. I couldn't find a license on this image. If there's a problem on it, please tell me.

Re: Tilemap (Creator-Defined Displayable)

Posted: Sun Apr 10, 2016 12:37 pm
by Yukari
How can I add a sprite of a character whoo can walking around? And how can I click on tiles and show text etc?

Re: Tilemap (Creator-Defined Displayable)

Posted: Sun Apr 10, 2016 12:45 pm
by nyaatrap
It's possible but I don't suggest... actually, I dropped this project for performance issue. I'd like to know if there's way to add something without performance lose.
It's not hard to add something, but it apparently shows lags on my core i3 laptop. core i5 plus more graphic board is minimum - is not something for ren'py game.

Re: Tilemap (Creator-Defined Displayable)

Posted: Wed Jun 12, 2019 1:41 pm
by zankizuna
Oh my gosh, i thought i was the only one working on a tilemap, this is amazing!
Here's my sample uguu
Our map code does look pretty similar!
Posts like these are so underappreciated hahaha

https://youtu.be/IK-aNQswghA

Re: Tilemap (Creator-Defined Displayable)

Posted: Sat Jun 15, 2019 2:50 pm
by M-77
Hello "zankizuna"! (And hello "nyaatrap" too) I watched your video. Can you provide us your code of the tilemap, or just the one for the movement, here please? I would like to combine it to my purpose when I have free time. I like to do a tilmap+movement+maybe a companion following (in some events)+action points (if clicked or hit ENTER) go to next screen or back to VN/txt story again. No battle system need for my project. This is interessting, one could add this in a VN to have some cutscene/as mini game. For distraction, like find the right chest in this maze.

Re: Tilemap (Creator-Defined Displayable)

Posted: Sun Jun 16, 2019 12:49 pm
by zankizuna
M-77 wrote: Sat Jun 15, 2019 2:50 pm Hello "zankizuna"! (And hello "nyaatrap" too) I watched your video. Can you provide us your code of the tilemap, or just the one for the movement, here please?
Thanks for watching ♡
My code is a bit unorganized, but i should make it available soon! I was planning to upload it on itch.io for sale or free but i need to make it easier to customize first. (It's a mess but it works)

If you had keys to my dev-team-only demo you will find its code is open source, but that's for our team only...

Please wait i guess.
I'd love to share it!

Re: Tilemap (Creator-Defined Displayable)

Posted: Mon Jun 17, 2019 10:32 am
by zankizuna
Maybe try this?