How to load a tilesheet?

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
bats
Newbie
Posts: 6
Joined: Sun Dec 18, 2016 4:29 am
Contact:

How to load a tilesheet?

#1 Post by bats »

I have a tilesheet that has 16x16 grids that define 256 different types of terrain. How can I render the individual terrains through blit()? I see that renpy has renpy.load_image(), but I'm unsure how to get renpy to then only render clips of the image. Most examples I've seen usually load individual images and the blits that, but I need to use a tilesheet (a single image).

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: How to load a tilesheet?

#2 Post by nyaatrap »

Do you really need to use blit? I think just crop final images by transform is more efficient. If you want to crop user defined displayable, use render.subsurface.
This is my personal experience, but blitting is slow operation. I think sending raw image to GPU directly, then show cropped image by transform is faster.

User avatar
Divona
Miko-Class Veteran
Posts: 678
Joined: Sun Jun 05, 2016 8:29 pm
Completed: The Falconers: Moonlight
Organization: Bionic Penguin
itch: bionicpenguin
Contact:

Re: How to load a tilesheet?

#3 Post by Divona »

"im.Crop()" should do it. Here is the link to documentation: https://www.renpy.org/doc/html/displaya ... ml#im.Crop

You could make a method that pick out those tile from the tileset like this:

Code: Select all

init python:
    def tile(x, y):
        global tile_size
        tile_size = 16
        return im.Crop("spritesheet.png", (tile_size * x, tile_size * y, tile_size, tile_size))
Then display them in "screen":

Code: Select all

screen gamemap():
    for y in xrange(10):
        for x in xrange(10):
            add tile(0, 0):
                xpos tile_size * x
                ypos tile_size * y
"tile(0, 0)" will get 16x16 tile from top left of the tileset.
"tile(1, 0)" will get the next 16x16 tile to the right of the tile above.
"tile(0, 1)" will get the 16x16 tile block below the top left tile.

Use them with list to store the map data.
Completed:
Image

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: How to load a tilesheet?

#4 Post by nyaatrap »

Divona wrote:"im.Crop()" should do it.

I don't suggest to use it because this operation is slow and it's only useful for fixed results that will be never changed.
When image cropping is changed by time, use LiveCrop or transform crop which is far faster operation.
(Honestly, I never think im.Crop is useful - it's obsoleted function.
Edit: I was wrong. I remember useful case. Some image modification only accept direct images or im.modified images, but not Transform nor LiveSomthing.)
Last edited by nyaatrap on Sun Dec 18, 2016 11:49 pm, edited 1 time in total.

bats
Newbie
Posts: 6
Joined: Sun Dec 18, 2016 4:29 am
Contact:

Re: How to load a tilesheet?

#5 Post by bats »

@nyaatrap Can you give a code sample? I don't quite understand how I just started learning renpy today, so I didn't know blit was slow.

In other engines, normally I would do something like build a quad, load the image as texture, then clip it and apply to the quad. Divona's way of doing it sounds like a familiar pattern, but if it's slow it would be great to know what the best way to do it in renpy would be.

Also, I found an old code sample from you: viewtopic.php?f=51&t=35608
It looks like you're blitting there, but how would you alternatively send "raw image to GPU directly, then show cropped image by transform", without blitting?

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: How to load a tilesheet?

#6 Post by nyaatrap »

bats wrote:Divona's way of doing it sounds like a familiar pattern, but if it's slow it would be great to know what the best way to do it in renpy would be.
Rewrite im.Crop to LiveCrop in the above code. Because im.Crop loads a spritesheet every time when it find new tile, but LiveCrop loads only once.
Also, I found an old code sample from you: viewtopic.php?f=51&t=35608
It looks like you're blitting there, but how would you alternatively send "raw image to GPU directly, then show cropped image by transform", without blitting?
I mean, simplily

Code: Select all

show image: crop x, y
is faster to crop an image than complicated tilemap code (blit & subsurface() cropping) after map is constructed. If it's ok that scrolling map is slow, and you want to create a huge map from spritesheets, then my code works effectively. Recent code is here https://github.com/nyaatrap/renpy-utili ... ilemap.rpy

bats
Newbie
Posts: 6
Joined: Sun Dec 18, 2016 4:29 am
Contact:

Re: How to load a tilesheet?

#7 Post by bats »

Hm, okay I tried to update @Divona code with @nyaatrap suggestions:


Code: Select all


label start:
    show screen doit
 
    e "rendered"

init python:
    def tile(x, y):
        return LiveCrop((32*x, 32*y, 32, 32), "test.png" )

screen doit():
    for y in xrange(100):
        for x in xrange(100):
            add tile(0,0):
                xpos 32 * x
                ypos 32 * y
Am I missing something, because I ran a test and @Divona's code (using im.Crop()) seems to load 1-2 secs faster than the above. It renders 100x100 just to test for speed (real game will do culling).

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: How to load a tilesheet?

#8 Post by nyaatrap »

Im.Crop loads png file then create cache from it, then use this cache. Cache is multiplied if it crops many, but one small portion is small.
LiveCrop don't create cache, but use png image directly.
Come to think of it, it hard to conclude which is lighter or faster. For example, if you use all tiles or changing them by time, LiveCrop is better. If a few or static, im.Crop.

Edit: After some test, in a case when same cropped image are reused many, im.Crop is better. Sorry for confusion.

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: How to load a tilesheet?

#9 Post by nyaatrap »

BTW, screen statement 'add' is the main reason why it's slow. If you want to raise performance, try my Tilemap so you could use only one add rather than (add image)*100.

Post Reply

Who is online

Users browsing this forum: Sugar_and_rice