Transforms without starting points

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
rames44a
Newbie
Posts: 11
Joined: Sat May 12, 2018 11:48 am
Contact:

Transforms without starting points

#1 Post by rames44a »

I've been experimenting with renpy.show_layer_at to dynamically alter the "viewport" into a Movie so that I can effectively zoom and pan while it's playing. I can define a few transitions:

Code: Select all

transform return_full_screen:
    linear 1.0 xpos 0 ypos 0 zpos 0

transform t1:
    linear 1.0 xpos 100 ypos 100 zpos -100
and then use something like

Code: Select all

def play_transform(t):
        renpy.show_layer_at([t], reset=False, camera=True)
When I call this passing in the transform object, the screen will pan and zoom the way I want it to. All good. But, what I want to do is generalize this, so that for different movies, I don't have to hard-code individual transforms. What I'd rather do is just have data structures, and build the appropriate transform on the fly.

Now, I know that I can code custom transforms (https://renpy.org/doc/html/trans_trans_ ... #Transform) by providing an appropriate function to alter the xpos, ypos and zpos values using the shown time base and animation time base. I've done that before. The kicker is this - the transforms coded above in "Ren'py language" don't have "from" and "to" values, just "to" values, but Ren'py is quite capable of running the transition from wherever things are now to the values I coded, over the period of time I coded. So, it's somehow figuring out the starting value on the fly so that it can interpolate to the end value.

So, my question is, how would I do the same? Specifically with the camera object, since that's what I'm using above. I don't know how to find out the "at the beginning of the transition" values. If I can do that, I can code an appropriate callable and use it with the Transform class, but I don't know how to get them.

Help?

User avatar
_ticlock_
Miko-Class Veteran
Posts: 910
Joined: Mon Oct 26, 2020 5:41 pm
Contact:

Re: Transforms without starting points

#2 Post by _ticlock_ »

rames44a wrote: Mon Feb 06, 2023 10:39 pm When I call this passing in the transform object, the screen will pan and zoom the way I want it to.
Can you give an example? I am not sure I understand.
rames44a wrote: Mon Feb 06, 2023 10:39 pm What I'd rather do is just have data structures, and build the appropriate transform on the fly.
What kind of data structures do you mean? Do you mean different values for the transform you mentioned or maybe a variable number of lines and values in the transform?

Anyway, some things that can be useful:
1) You can pass arguments to transform

Code: Select all

transform t1(duration = 1.0, x = 100, y = 100, z = -100):
    linear duration xpos x ypos y zpos z
You can also use some global variables if that is more convenient.

You can create several templates of transforms. Using your data structure you can select one of them and pass the necessary arguments.

2) You can also use function in the transform.

rames44
Veteran
Posts: 233
Joined: Sun May 29, 2016 4:38 pm
Contact:

Re: Transforms without starting points

#3 Post by rames44 »

I’m well aware that you can write transforms using functions, as I stated in the original post. That’s what I want to do. My point is that, to do that, the function has to be able to lerp the values from their starting position to their final position. So, how do I find the starting positions? The function will get passed the transform that it’s supposed to alter as part of its callback processing, but where do I find the transform object beforehand so I can pull the starting values?

That being said, if I can dynamically generate transforms on the fly using Ren’py language and variables, I MIGHT be able to make that work. The issue was that where I want to do this is currently buried in Python.

rames44a
Newbie
Posts: 11
Joined: Sat May 12, 2018 11:48 am
Contact:

Re: Transforms without starting points

#4 Post by rames44a »

My first version of the question had a lot of extraneous stuff in it. Let me distill it down:

Here's a more succinct version.

Clearer background:
  • I want to dynamically alter the transform applied to the Ren'py camera. From Python. To create "pan and zoom" effects.
  • renpy.show_layer_at with camera=True does what I need it to. If I create a transform using "Ren'py language", I can apply it using this function.
  • The problem is that I really don't want to code the transforms in Ren'py language - there would be too many of them. What I'd like to do is dynamically create a Transform object that uses a function to do its work. I know how to do that in the "normal" case.
  • When the function is called, it gets passed the transform object attached to the target object (the camera) so that it can alter that transform. So, I know what attributes to alter, and I know the values I want to lerp them to over time.
  • But, I need to know the "from" values - the values of the attributes before I apply the transform - so that I can do the lerping.
So, the question is

"When it's time to move the camera, how do I find the current transform attached to the camera so that I can retrieve the "from" values."

User avatar
_ticlock_
Miko-Class Veteran
Posts: 910
Joined: Mon Oct 26, 2020 5:41 pm
Contact:

Re: Transforms without starting points

#5 Post by _ticlock_ »

rames44 wrote: Wed Feb 08, 2023 1:47 pm That’s what I want to do. My point is that, to do that, the function has to be able to lerp the values from their starting position to their final position.
I believe transforms does not use "starting position". It uses current properties, current st, at (timebase of the displayable), warper, and "final" properties to calculate new intermediate properties.

For example:

linear 1.0 xpos 100
at st = 0.5, it knows the last xpos (trans.xpos)
to calculate new xpos, you need to find the difference between xpos 100 and trans.xpos.
Knowing current st and warper and difference (100 - trans.xpos) you can calculate new xpos.

User avatar
_ticlock_
Miko-Class Veteran
Posts: 910
Joined: Mon Oct 26, 2020 5:41 pm
Contact:

Re: Transforms without starting points

#6 Post by _ticlock_ »

rames44a wrote: Wed Feb 08, 2023 2:30 pm My first version of the question had a lot of extraneous stuff in it. Let me distill it down:
I think I get the idea. But I am not sure why you can't use transform with arguments or function inside transform.

Can you give a simple example of what your "data structure" would consist of? Or how would you like to interpolate from starting values to final values on the fly in the python function?

rames44a
Newbie
Posts: 11
Joined: Sat May 12, 2018 11:48 am
Contact:

Re: Transforms without starting points

#7 Post by rames44a »

_ticlock_ wrote: Wed Feb 08, 2023 3:07 pm I believe transforms does not use "starting position". It uses current properties, current st, at (timebase of the displayable), warper, and "final" properties to calculate new intermediate properties.

For example:

linear 1.0 xpos 100
at st = 0.5, it knows the last xpos (trans.xpos)
to calculate new xpos, you need to find the difference between xpos 100 and trans.xpos.
Knowing current st and warper and difference (100 - trans.xpos) you can calculate new xpos.
Yes. Exactly. However, how do you get the original trans.xpos so that you can calculate the difference? That's what I mean by "starting position" - the trans.xpos BEFORE the new transform is applied. If you don't know where you're starting and ending, you can't interpolate between them, right? So, what I'm calling "starting position" is exactly what you're calling "current properties." Nothing more, nothing less. Just differences in terminology.
_ticlock_ wrote: Wed Feb 08, 2023 4:03 pm I think I get the idea. But I am not sure why you can't use transform with arguments
Please re-read the part that says "in Python." If you can show me how, IN PYTHON, to code a "transform with arguments," then we're done. AFAIK, the only way to do this is in Ren'py language, not in Python.
_ticlock_ wrote: Wed Feb 08, 2023 4:03 pm or function inside transform.
Please re-read the multiple parts where I say that this is EXACTLY what I'm trying to do. I'm trying to do EXACTLY what you're describing above in terms of using st to go from the original ("current") position to a new position. But to do that, I need to be able to find the original ("current") position.
_ticlock_ wrote: Wed Feb 08, 2023 4:03 pm Can you give a simple example of what your "data structure" would consist of?
Please ignore the specifics of this, as it's not germane to the discussion. Assume that I use this to figure out, based on user input, the desired "next values" of the transform that I wish to smoothly transition to. The camera is where it is right now - I want it to go somewhere else.
_ticlock_ wrote: Wed Feb 08, 2023 4:03 pm Or how would you like to interpolate from starting values to final values on the fly in the python function?
Exactly as you describe it earlier - where you calculate the difference between the original trans.xpos, the desired final trans.xpos, and then use the st and warper to figure out where you are at any given point.


With respect, you're going round and round on things that I've already covered. I understand that you're trying to help, but so far all you've done is use different terminology than mine ("current properties" or "trans.xpos" instead of "starting position") and explain stuff that I said that I already understand.

Let me boil this down to a very, VERY simple question, as follows:

At any given time, how do I go about obtaining the current transform on the Ren'py camera? The current "xpos" value, to use your example above.

That's it. That's all I need. Everything else I know how to do, as I've tried to explain. That one question is the part I DON'T understand. If you can't answer that question, then, with respect, you're not helping me.

User avatar
_ticlock_
Miko-Class Veteran
Posts: 910
Joined: Mon Oct 26, 2020 5:41 pm
Contact:

Re: Transforms without starting points

#8 Post by _ticlock_ »

rames44a wrote: Thu Feb 09, 2023 12:19 am you're going round and round on things that I've already covered. I understand that you're trying to help, but so far all you've done is use different terminology than mine ("current properties" or "trans.xpos" instead of "starting position") and explain stuff that I said that I already understand.

Let me boil this down to a very, VERY simple question, as follows:

At any given time, how do I go about obtaining the current transform on the Ren'py camera? The current "xpos" value, to use your example above.

That's it. That's all I need. Everything else I know how to do, as I've tried to explain. That one question is the part I DON'T understand. If you can't answer that question, then, with respect, you're not helping me.
Possibly, I misunderstand you. In my previous post, by "starting position" - I meant properties at timebase st = 0, while "current properties" are properties at current timebase st.

I asked for an example to get an idea of what would be a better approach for the task.

Here are some ideas that can be useful in your case (not polished examples):

1) Use transform with arguments and ignore the current position:

Code: Select all

transform t_t(duration = 1.0, x_pos = 0, y_pos = 0):
    linear duration xpos x_pos ypos y_pos
Based on user input or other things you can apply some new position

Code: Select all

        renpy.show_layer_at([t_t(5.0, 500, 500)], reset=False, camera=True)
cons: the moving speed depends on "current position" which can be a problem

2) Use transform with function:

Code: Select all

transform dyn_t:
    function dynamic_transform
(or pass this function to Transform)

Code: Select all

default t_xpos = 500
default t_ypos = 500
default t_speed = 100.0
default t_old_st = 0

init python:
    def dynamic_transform(trans, st, at):
        global t_xpos, t_ypos, t_old_st, t_speed
        xpos, ypos = trans.pos
        if xpos == None:
            xpos = 0
        if ypos == None:
            ypos = 0
        if xpos != t_xpos or ypos !=  t_ypos:
            if st > t_old_st:
                dt = st - t_old_st
            else:
                t_old_st = st
                
            # Using dt, t_xpos, t_ypos, t_speed you can calculate new pos
            ...
            trans.pos = absolute(xpos), absolute(ypos)
        return 0
Based on user input or other things you can apply some new position

Code: Select all

    def new_position(xpos, ypos):
        global t_xpos, t_ypos
        t_xpos, t_ypos = xpos, ypos
cons: You need to manually do the transform function

3) Workaround using transform with function to track current properties

Code: Select all

default transform_properties = {"xpos": 0, "ypos": 0, "duration": 1.0}

transform t_properties:
    function get_transform_properties
init python:
    def get_transform_properties(trans, st, at):
        global transform_properties
        xpos, ypos = trans.pos
        if xpos == None:
            xpos = 0
        if ypos == None:
            ypos = 0
        transform_properties["xpos"] = xpos
        transform_properties["ypos"] = ypos
        return 0.1

Code: Select all

init python:
    def new_transform_properties(xpos = 0, ypos = 0):
        global transform_properties
        old_xpos = transform_properties["xpos"]
        old_ypos = transform_properties["ypos"]
        if xpos != old_xpos or ypos !=  old_ypos:
            distance = math.hypot(old_xpos - xpos, old_ypos - ypos)
            transform_properties["duration"] = distance/t_speed
            transform_properties["xpos"] = xpos
            transform_properties["ypos"] = ypos

    def adjust_transform(xpos = 0, ypos = 0):
        new_transform_properties(xpos, ypos)
        renpy.show_layer_at([t_properties, t_t(transform_properties["duration"],
                transform_properties["xpos"], transform_properties["ypos"])
                ], reset=False, camera=True)
You need initially to apply transform `t_properties` to track current properties
then you can use adjust_transform to apply new position knowing current properties.

cons: you need to apply additional transform `t_properties` to track current properties.

rames44a
Newbie
Posts: 11
Joined: Sat May 12, 2018 11:48 am
Contact:

Re: Transforms without starting points

#9 Post by rames44a »

Understand the confusion - I was using "current position" to mean "current position before applying the new transform."

Your options #2 and #3 both require external tracking of the transform attributes. I was hoping to avoid that and use the "real" ones, since they are the real source of truth. Although the idea of applying a "null" transform ahead of the real one to extract the values is certainly interesting.

My point is that if #1 works, Ren'py itself must have a way of accessing the starting values of the transform properties. What I was hoping to accomplish was to do the same thing myself.

I've been digging into the source code. It appears that the Ren'py Context class has a member variable named "scene_lists" which is an instance of renpy.display.core.SceneLists. The SceneLists class appears to hold the camera transform. So, off to experiment with that...

User avatar
_ticlock_
Miko-Class Veteran
Posts: 910
Joined: Mon Oct 26, 2020 5:41 pm
Contact:

Re: Transforms without starting points

#10 Post by _ticlock_ »

rames44a wrote: Thu Feb 09, 2023 10:09 am Understand the confusion - I was using "current position" to mean "current position before applying the new transform."

Your options #2 and #3 both require external tracking of the transform attributes. I was hoping to avoid that and use the "real" ones, since they are the real source of truth. Although the idea of applying a "null" transform ahead of the real one to extract the values is certainly interesting.

My point is that if #1 works, Ren'py itself must have a way of accessing the starting values of the transform properties. What I was hoping to accomplish was to do the same thing myself.

I've been digging into the source code. It appears that the Ren'py Context class has a member variable named "scene_lists" which is an instance of renpy.display.core.SceneLists. The SceneLists class appears to hold the camera transform. So, off to experiment with that...
You want to directly access the transform object that is linked to the camera. Actually, that is a good idea. I believe you can get it using the following:

Code: Select all

    trans = renpy.game.context().scene_lists.camera_transform["master"]
I did a quick test in the console and it seems to work fine.

Although, I am not sure if using it can create any kind of problems.

rames44a
Newbie
Posts: 11
Joined: Sat May 12, 2018 11:48 am
Contact:

Re: Transforms without starting points

#11 Post by rames44a »

_ticlock_ wrote: Thu Feb 09, 2023 3:22 pm You want to directly access the transform object that is linked to the camera. Actually, that is a good idea.
That was what I was trying to ask from the beginning. Perhaps not clearly, but...
_ticlock_ wrote: Thu Feb 09, 2023 3:22 pm I believe you can get it using the following:

Code: Select all

    trans = renpy.game.context().scene_lists.camera_transform["master"]
Yes, exactly.
_ticlock_ wrote: Thu Feb 09, 2023 3:22 pm I did a quick test in the console and it seems to work fine.

Although, I am not sure if using it can create any kind of problems.
Of course, since this isn't a documented part of the interface, the danger would be that this might not be portable from one Ren'py version to the next.

Post Reply

Who is online

Users browsing this forum: nicedracula