Ren'Py matrixcolor transform resets image position?

The Rogue Trader

Active Member
Sep 12, 2021
510
756
OK, apparently I coded myself in a corner again.

I'm using character sprites, but I want to have some leeway with their relative height (and my artist is giving them in 2x resolution).
Easy, I define them with the correct size and position:
Python:
init:
    image Alice nervous:
        "chars/alice-nervous-talk.png"
        zoom 0.50
        ypos 1.1
Now, I want to keep the same sprite for scenes during daytime, nighttime and with torch/candle light (medieval fantasy setting).
I looked around and it's easy to do with a :
Python:
init: 
    transform firelit:
        matrixcolor TintMatrix("#fcd390")
    transform moonlit:
        matrixcolor TintMatrix("#9d9ec4")

But when I apply the transform,
Python:
show BG 0_1_room
show Alice nervous at firelit
the sprite ends in the top left corner (and also autofitted to the screen height, I think, for sure it's not the scale that I did set).
It's like the transform sets xypos (0,0) instead of letting the position well alone as I would expect from a well-behaved transform. Without the transform, the sprite is shown with the correct scale and position.
I can apply a second transform to adjust the position, but I believe it would be a very inelegant and inefficient solution.

I suppose I'm making a very dumb mistake down the line, but my google-fu is failing me.

(The transforms are loaded before the image declaration, if it's of any help.)
 

MidnightArrow

Active Member
Aug 22, 2021
500
451
Afaik a transform in Ren'py language is just an instance of the Python Transform() class. So when you instantiate it, all prior transforms are replaced by whatever the class-defined default is (probably xypos (0, 0)) except for the fields you overrode.

There's probably multiple ways to solve this. The docs say you can use a comma-separated list of transforms so I'd probably just make the zoom and ypos into a separate transform since they seem like they'll be used for multiple sprites anyway.

show Alice nervous at zoomed, firelit
 

The Rogue Trader

Active Member
Sep 12, 2021
510
756
Afaik a transform in Ren'py language is just an instance of the Python Transform() class. So when you instantiate it, all prior transforms are replaced by whatever the class-defined default is (probably xypos (0, 0)) except for the fields you overrode.

There's probably multiple ways to solve this. The docs say you can use a comma-separated list of transforms so I'd probably just make the zoom and ypos into a separate transform since they seem like they'll be used for multiple sprites anyway.

show Alice nervous at zoomed, firelit
Yes, that's a solution, but I don't partucularly like it, as I'll need to have a long series of transforms (zoom 110%, zoom 115%, zoom 120%, zoom 95%, height +5%, height +10%, etc etc depending from the needed granularity) and I'd have to apply them in the script, instead of having them as image parameters for each character as need arises.
Very inelegant, at this point I wonder if it isn't better just to modify the colour directly on the sprite in postwork and call it a day with 3 series of sprites for each character.

Thank you for your input, I didn't notice that transforms are a Python class, I'll try to delve there and see if there's a way for telling them to respect previous parameters.
 

Saki_Sliz

Well-Known Member
May 3, 2018
1,403
1,011
I've noticed similar frustrating behavior, and having little to no renpy experience, all I've been able to find is similar answers where a lot of what ren'py does in cool conceptually, but execution wise tends to have some short comings. I've been having to accept ugly code.

what's worked for me is that some transforms when defined, don't override certain values (I haven't figured out the logic to this yet), in your case, maybe trying doing show Alice nervous at firelit, zoomed with the firelit first and see if the zoomed transform doesn't override the color matrix.
 

MidnightArrow

Active Member
Aug 22, 2021
500
451
what's worked for me is that some transforms when defined, don't override certain values (I haven't figured out the logic to this yet), in your case, maybe trying doing show Alice nervous at firelit, zoomed with the firelit first and see if the zoomed transform doesn't override the color matrix.
There is no "logic". It's like PyTom hits a roadblock every time he codes the program and shoves some ugly hack in wherever he feels like it. It's totally inelegant and ugly, and it has all sorts of special exceptions under the hood you just need to memorize.
 

The Rogue Trader

Active Member
Sep 12, 2021
510
756
OK, I found a decent compromise. Instead of having an external transform to modify the displayables, I make two/three displayables from each image.

Python:
init:
    image Alice nervous:
        "chars/alice-nervous-talk.png"
        zoom 0.50
        ypos 1.1

    image Alice nervous firelit:
        matrixcolor TintMatrix("#fcd390")
        "chars/alice-nervous-talk.png"
        zoom 0.50
        ypos 1.1
In hindsight, I could have gotten there sooner.
 
  • Like
Reactions: Saki_Sliz

The Rogue Trader

Active Member
Sep 12, 2021
510
756
what's worked for me is that some transforms when defined, don't override certain values (I haven't figured out the logic to this yet),
Thanks for the useful info! As I always used custom transforms only to modify the position of the displayable, I never noticed this behaviour before.
I can live with it lacking a logic, but I'd love to have it somewhat documented (like a checklist of what overrides what).

in your case, maybe trying doing show Alice nervous at firelit, zoomed with the firelit first and see if the zoomed transform doesn't override the color matrix.
I'm sure that the syntax you're using works as intended (I already checked with the "center" transform when I made the first post), but my issue was that the custom "firelit" transform was overriding all the transforms already coded in the "Alice nervous" displayable (including the default position).
 

gojira667

Member
Sep 9, 2019
325
320
I can't reproduce the issue. Your original example works fine for me with renpy-7.5.3-sdk. I did use different values in the image definition as my 'Alice' image has different dimensions. Both show in the exact same position on screen.

Are your source images all different sizes? While I haven't worked much with sprites, does it not make sense to standardize the image dimensions and reduce the per image transforms?
 

The Rogue Trader

Active Member
Sep 12, 2021
510
756
I can't reproduce the issue. Your original example works fine for me with renpy-7.5.3-sdk. I did use different values in the image definition as my 'Alice' image has different dimensions. Both show in the exact same position on screen.
Uuhhh.
I'm using renpy-8.0.1-sdk. I already had a faint suspicion that this behaviour could be a bug introduced by the last version, as I found a 2011 post saying that a similar behaviour had been corrected in 6.1
That suspicion is growing stronger, now.

Are your source images all different sizes? While I haven't worked much with sprites, does it not make sense to standardize the image dimensions and reduce the per image transforms?
That was the first image produced by the artist. While standardizing the renders is definitely the best-sounding practice, I'd rather not resize the image files, losing quality.
Also, to be honest, my previous experiences with rendering sprites weren't very positive in that regard, so I believe that maintaining the possibility of adjusting the height of the characters from the code according to my needs sounds the safest way.
I don't want to send back to the artist a bunch of sprites to be re-rendered because "I don't like that they're taller than the other character".
 

gojira667

Member
Sep 9, 2019
325
320
I don't want to send back to the artist a bunch of sprites to be re-rendered because "I don't like that they're taller than the other character".
Well I meant that they would be taller, but it would be the one transform. E.G. source files, standing sprites with feet: char1 = (477,130), char2 = (300, 125), char3 = (188, 250). Normalize the image dimensions (canvas size) to (477,250) for all of them. Placing the sprites feet in the same basic location (bottom-left aligned).

Then you define the transform to move the feet of the sprite to wherever, upper-left. That one transform would place any of the sprites in the same location.
 

The Rogue Trader

Active Member
Sep 12, 2021
510
756
Well I meant that they would be taller, but it would be the one transform. E.G. source files, standing sprites with feet: char1 = (477,130), char2 = (300, 125), char3 = (188, 250). Normalize the image dimensions (canvas size) to (477,250) for all of them. Placing the sprites feet in the same basic location (bottom-left aligned).

Then you define the transform to move the feet of the sprite to wherever, upper-left. That one transform would place any of the sprites in the same location.
Yes, that would most certainly be the easiest procedure on the coding side. It also feels like I'm making it Somebody Else Problem.

In other words: I'm not too willing to assume that'll the character renders will all always be shot with exactly the same camera angle, at exactly the same distance, etc.
When I did the same job, I ended up changing the camera's distance and angle several times before finding the optimum (did I ever?), and each time I had to re-render all the previous characters. OK, I'm probably the sloppiest person on this site, but stuff happens, especially in a long, ongoing project that has just started.
I can accept the loss (with some marginal swearing) when I'm the one doing the job, but if I have a way to correct incidents without bloodshed I'd be way happier!