[Solved] How to use a variable as an image attribute?

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
User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

[Solved] How to use a variable as an image attribute?

#1 Post by yon » Sun Aug 21, 2022 2:52 am

Hello again everyone, I have another question.

Let's say I have two variants of a sprite, one where a character is wearing cold weather clothing and one where the character is wearing hot weather clothing. The attributes as I have it now might look like:

Code: Select all

yui cold pout
However, because events don't happen linearly -- that is to say, an event can take place in either a warm or cold part of the year, whenever the player decides to trigger it -- I would like to figure out a way to display the sprite where the cold/warm aspect can be swapped out by using a variable. So, for example, it might look like this --

Code: Select all

label june:
    $ v_season = "warm" 

    call yui_logic

# yui logic tree determines which yui label to display rather than linking to a single one 

# yui logic tree decides to show yui event #5

label yui_05:

    scene black
    show yui v_season pout
Ideally, the code would look at v_season, see that it has been set to "warm", and then essentially take it as having the attribute "warm" and display the appropriate sprite.

I'm still a little shaky on how exactly image attributes work, but if I can get it to recognize a variable's value as an attribute, should that not work as though I had just put the attribute in directly?

I'd like to do something similar for backgrounds, which also use the "warm/cold" division. I assume it would be the same process?
Last edited by yon on Fri Aug 26, 2022 4:47 pm, edited 1 time in total.

User avatar
AVNSnax
Regular
Posts: 35
Joined: Sun Feb 06, 2022 12:11 am
itch: avnsnax
Contact:

Re: How to use a variable as an image attribute?

#2 Post by AVNSnax » Tue Aug 23, 2022 3:54 pm

If I'm not mistaken, Ren'Py resolves the attributes for an image at compile time instead of runtime. It tries several methods to resolve an actual filename from the arguments given in the show statement. In your example, Ren'Py is going to take your v_season variable name instead of its value to derive an image name that doesn't exist.

The simplest solution is to mangle the image name yourself by calling show's python equivalent, renpy.show(), and pass it a string with the mangled image name + attributes.

Code: Select all

    $ renpy.show("yui {} pout".format(v_season), ...)
This would work for your background images as well.

User avatar
Imperf3kt
Lemma-Class Veteran
Posts: 3636
Joined: Mon Dec 14, 2015 5:05 am
Location: Your monitor
Contact:

Re: How to use a variable as an image attribute?

#3 Post by Imperf3kt » Tue Aug 23, 2022 7:31 pm

Warning: May contain trace amounts of gratuitous plot.
pro·gram·mer (noun) An organism capable of converting caffeine into code.

Current project: GGD Mentor
Free Android GUI - Updated occasionally
Twitter
Imperf3kt Blackjack - a WIP blackjack game for Android made using Ren'Py

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to use a variable as an image attribute?

#4 Post by yon » Fri Aug 26, 2022 5:09 am

Imperf3kt wrote:
Tue Aug 23, 2022 7:31 pm
There is also layeredimage
https://www.renpy.org/doc/html/layeredi ... red-images
I think I'm having trouble understanding this. I've looked at it in the past, and I think it would require me to create a bunch of different individual parts of the sprite on different layers, which I CAN do, but is a little weirder in some cases than just displaying it as is (or maybe I could just have each entire sprite as its own "layer" atop a blank base?), but what I really want to do is to be able to conditionally call a different image using the same language in each case based on a variable being changed.

It looks like in this case, it creates a sprite which has a different outcome by combining the parts when you use a different attribute to modify the base. What I'm trying to do is allow for one aspect of the same code to be changed conditionally without changing the language.

And I'd have to do this for every character with seasonal outfits and every seasonal background, too. Unless I'm misunderstanding this, it seems like the only way to use that to achieve what I'm trying to do is manually redefining what the attribute means for each sprite and its variants.

So, because I may just be massively misreading this page and what layeredimage can do, is it possible to use layered image to accomplish the following scenario?

Code: Select all

# the season is set to "cold", "warm", or "snow" at some point in the story 

# the same event is capable of being called during any season and needs to have its value changed

# the event gets called after the season value has been set elsewhere

scene bg plaza [season]
What I'm looking for is an ability for something to stand in for that [season] bit and have its value replaced without needing to manually do it, because the scene can be called at any given time and not specific to any one season

Again, I'm sorry if I'm misunderstanding, I just don't understand how using layeredimage would help since it seems to involve combining elements into a single image by using an attribute, rather than allowing for a single attribute's value to be swapped as needed

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to use a variable as an image attribute?

#5 Post by yon » Fri Aug 26, 2022 5:32 am

AVNSnax wrote:
Tue Aug 23, 2022 3:54 pm
If I'm not mistaken, Ren'Py resolves the attributes for an image at compile time instead of runtime. It tries several methods to resolve an actual filename from the arguments given in the show statement. In your example, Ren'Py is going to take your v_season variable name instead of its value to derive an image name that doesn't exist.

The simplest solution is to mangle the image name yourself by calling show's python equivalent, renpy.show(), and pass it a string with the mangled image name + attributes.

Code: Select all

    $ renpy.show("yui {} pout".format(v_season), ...)
This would work for your background images as well.
Is that something I would have to do when defining it only, or is that every single time I want to show any sort of image with a conditional attribute? I'm not sure whether I would need to fill out every single part of that (name, at_list, layer, what, zorder, tag, behind), either?

But I would be able to use a variable in the string which is being used as the sprite's name?

Am I able to put in other attributes that would be included there, but AREN'T variables? That is, how would I use this to implement the following?

(Character name) (season variable) (outfit type) (expression)

Yui [season] casual pout

I'm sorry, I'm just really confused about how this actually works. Why is it that putting (v_season) directly after .format inserts it into the {} braces? In this case, would I just have to write out the entire rest of the file name (example, "yui {} casual pout".png(v_season), right)?

What layer would I use? How would I make sure that it operates as normal by showing it above the background? Using scene seems to get rid of all of the images being shown above it, unless I'm wrong, so how how do I replicate that without manually hiding it each time?

Would I actually have to manually hide each sprite after I use it and want to swap to a new one?

I'm sorry for so many questions, I just want to understand how this works and why. I don't see this information on the documentation listed, unless I've missed it somehow.

User avatar
Ocelot
Eileen-Class Veteran
Posts: 1882
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: How to use a variable as an image attribute?

#6 Post by Ocelot » Fri Aug 26, 2022 5:47 am

$ renpy.show("stuff") is eqivalent to show stuff. Every default is the same. Everything else you provide if you would provide it for show statement in the script.
yon wrote:
Fri Aug 26, 2022 5:32 am
Am I able to put in other attributes that would be included there, but AREN'T variables? That is, how would I use this to implement the following?

(Character name) (season variable) (outfit type) (expression)

Yui [season] casual pout
$ renpy.show("yui {} causal pout".format(v_season))
yon wrote:
Fri Aug 26, 2022 5:32 am
Why is it that putting (v_season) directly after .format inserts it into the {} braces?
Basic Python: https://docs.python.org/3/library/stdty ... str.format
yon wrote:
Fri Aug 26, 2022 5:32 am
In this case, would I just have to write out the entire rest of the file name (example, "yui {} casual pout".png(v_season), right)?
No. You want to show an image with tags and attributes, not some file.
yon wrote:
Fri Aug 26, 2022 5:32 am
What layer would I use? How would I make sure that it operates as normal by showing it above the background?
Everything should work ny default.

yon wrote:
Fri Aug 26, 2022 5:32 am
Using scene seems to get rid of all of the images being shown above it, unless I'm wrong, so how how do I replicate that without manually hiding it each time?
scene something is a lie. Actually what happens, it silently transformed to:

Code: Select all

scene
show something
Just use scene statement without arguments before showing your image.
yon wrote:
Fri Aug 26, 2022 5:32 am
Would I actually have to manually hide each sprite after I use it and want to swap to a new one?
Everything works as if displayed by show stuff statement. So, no.
< < insert Rick Cook quote here > >

User avatar
Imperf3kt
Lemma-Class Veteran
Posts: 3636
Joined: Mon Dec 14, 2015 5:05 am
Location: Your monitor
Contact:

Re: How to use a variable as an image attribute?

#7 Post by Imperf3kt » Fri Aug 26, 2022 6:37 am

yon wrote:
Fri Aug 26, 2022 5:09 am
Imperf3kt wrote:
Tue Aug 23, 2022 7:31 pm
There is also layeredimage
https://www.renpy.org/doc/html/layeredi ... red-images
I think I'm having trouble understanding this. I've looked at it in the past, and I think it would require me to create a bunch of different individual parts of the sprite on different layers, which I CAN do, but is a little weirder in some cases than just displaying it as is (or maybe I could just have each entire sprite as its own "layer" atop a blank base?), but what I really want to do is to be able to conditionally call a different image using the same language in each case based on a variable being changed.

It looks like in this case, it creates a sprite which has a different outcome by combining the parts when you use a different attribute to modify the base. What I'm trying to do is allow for one aspect of the same code to be changed conditionally without changing the language.

And I'd have to do this for every character with seasonal outfits and every seasonal background, too. Unless I'm misunderstanding this, it seems like the only way to use that to achieve what I'm trying to do is manually redefining what the attribute means for each sprite and its variants.

So, because I may just be massively misreading this page and what layeredimage can do, is it possible to use layered image to accomplish the following scenario?

Code: Select all

# the season is set to "cold", "warm", or "snow" at some point in the story 

# the same event is capable of being called during any season and needs to have its value changed

# the event gets called after the season value has been set elsewhere

scene bg plaza [season]
What I'm looking for is an ability for something to stand in for that [season] bit and have its value replaced without needing to manually do it, because the scene can be called at any given time and not specific to any one season

Again, I'm sorry if I'm misunderstanding, I just don't understand how using layeredimage would help since it seems to involve combining elements into a single image by using an attribute, rather than allowing for a single attribute's value to be swapped as needed
Sorry, I was thinking of images used in a screen.

With a little extra python, you can have something like this: (psuedo code. Probably has a couple of errors)

Code: Select all

layeredimage fred:
    always "images/fred base.png"
    
    group Season:
        attribute winter:
            "images/fred winter coat.png"
            
            
            

screen myScreen():
    imagebutton:
        idle 'Fred {}'.format(season.season)
        action NullAction()
    
    
    
    
init python:
    class Season(object):
        def __init__(self, name, season):
            self.name = name
            self.season = season


define summer = myCharacter("Summer", "summer")
define fall = myCharacter("Fall", "fall")
define winter = myCharacter("Winter", "winter")
define spring = myCharacter("Spring", "spring")

Warning: May contain trace amounts of gratuitous plot.
pro·gram·mer (noun) An organism capable of converting caffeine into code.

Current project: GGD Mentor
Free Android GUI - Updated occasionally
Twitter
Imperf3kt Blackjack - a WIP blackjack game for Android made using Ren'Py

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to use a variable as an image attribute?

#8 Post by yon » Fri Aug 26, 2022 1:29 pm

$ renpy.show("yui {} causal pout".format(v_season))
Basic Python: https://docs.python.org/3/library/stdty ... str.format
Sorry, I thought that ".format" being used there was meant to refer to the format of the file, I didn't realize it was referring to a string formatting operation.
Just use scene statement without arguments before showing your image.
Okay, thank you.
$ renpy.show("stuff") is eqivalent to show stuff. Every default is the same. Everything else you provide if you would provide it for show statement in the script.
So, you're saying that the only difference is that, rather than using, say:

Code: Select all

show yui cold casual pout at right
I would use

Code: Select all

$ renpy.show("yui {} causal pout".format(v_season), right)
Is that correct?

How would I include transitions like moveinright in that case? Would it be this?

Code: Select all

$ renpy.show("yui {} causal pout".format(v_season), right) with moveinright
Thank you again for your patience, as always.

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to use a variable as an image attribute?

#9 Post by yon » Fri Aug 26, 2022 1:47 pm

Imperf3kt wrote:
Fri Aug 26, 2022 6:37 am
yon wrote:
Fri Aug 26, 2022 5:09 am
Imperf3kt wrote:
Tue Aug 23, 2022 7:31 pm
There is also layeredimage
https://www.renpy.org/doc/html/layeredi ... red-images
I think I'm having trouble understanding this. I've looked at it in the past, and I think it would require me to create a bunch of different individual parts of the sprite on different layers, which I CAN do, but is a little weirder in some cases than just displaying it as is (or maybe I could just have each entire sprite as its own "layer" atop a blank base?), but what I really want to do is to be able to conditionally call a different image using the same language in each case based on a variable being changed.

It looks like in this case, it creates a sprite which has a different outcome by combining the parts when you use a different attribute to modify the base. What I'm trying to do is allow for one aspect of the same code to be changed conditionally without changing the language.

And I'd have to do this for every character with seasonal outfits and every seasonal background, too. Unless I'm misunderstanding this, it seems like the only way to use that to achieve what I'm trying to do is manually redefining what the attribute means for each sprite and its variants.

So, because I may just be massively misreading this page and what layeredimage can do, is it possible to use layered image to accomplish the following scenario?

Code: Select all

# the season is set to "cold", "warm", or "snow" at some point in the story 

# the same event is capable of being called during any season and needs to have its value changed

# the event gets called after the season value has been set elsewhere

scene bg plaza [season]
What I'm looking for is an ability for something to stand in for that [season] bit and have its value replaced without needing to manually do it, because the scene can be called at any given time and not specific to any one season

Again, I'm sorry if I'm misunderstanding, I just don't understand how using layeredimage would help since it seems to involve combining elements into a single image by using an attribute, rather than allowing for a single attribute's value to be swapped as needed
Sorry, I was thinking of images used in a screen.

With a little extra python, you can have something like this: (psuedo code. Probably has a couple of errors)

Code: Select all

layeredimage fred:
    always "images/fred base.png"
    
    group Season:
        attribute winter:
            "images/fred winter coat.png"
            
            
            

screen myScreen():
    imagebutton:
        idle 'Fred {}'.format(season.season)
        action NullAction()
    
    
    
    
init python:
    class Season(object):
        def __init__(self, name, season):
            self.name = name
            self.season = season


define summer = myCharacter("Summer", "summer")
define fall = myCharacter("Fall", "fall")
define winter = myCharacter("Winter", "winter")
define spring = myCharacter("Spring", "spring")

Would I have to call that screen every time I change the weather? Do I need to click the imagebutton for it to work?

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to use a variable as an image attribute?

#10 Post by yon » Fri Aug 26, 2022 2:21 pm

Update: using the $ renpy.show("yui {} causal pout".format(v_season)) method DOES work! I'm just not sure how to use transitions with it yet.

User avatar
Ocelot
Eileen-Class Veteran
Posts: 1882
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: How to use a variable as an image attribute?

#11 Post by Ocelot » Fri Aug 26, 2022 3:11 pm

yon wrote:
Fri Aug 26, 2022 1:29 pm
So, you're saying that the only difference is that, rather than using, say:

Code: Select all

show yui cold casual pout at right
I would use

Code: Select all

$ renpy.show("yui {} causal pout".format(v_season), right)
Is that correct?
wrote:at_list
A list of transforms that are applied to the image. The equivalent of the at property.

Code: Select all

$ renpy.show("yui {} causal pout".format(v_season), at_list=[right])
yon wrote:
Fri Aug 26, 2022 1:29 pm
How would I include transitions like moveinright in that case? Would it be this?

Code: Select all

$ renpy.show("yui {} causal pout".format(v_season), right) with moveinright
Thank you again for your patience, as always.
https://www.renpy.org/doc/html/displayi ... statements
do_stuff with transition is equivalent to

Code: Select all

with None
do_stuff
with transition
So you can do:

Code: Select all

# first with None is not nessesary in 99% cases. Usually only needed to les previous transition run before this one
$ renpy.show("yui {} causal pout".format(v_season), at_list=[right])
with moveinright
If you doing it as part of Python function or block, Python equivalen would be $ renpy.with_statement(moveinright)
< < insert Rick Cook quote here > >

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to use a variable as an image attribute?

#12 Post by yon » Fri Aug 26, 2022 4:47 pm

It looks like it all works! Thank you again, everyone. Using this method is going to make it a lot easier.

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Majestic-12 [Bot]