the effect of ATL on Renpy customisation

In this forum we discuss the future of Ren'Py, both bug fixes and longer-term development. Pre-releases are announced and discussed here.
Post Reply
Message
Author
User avatar
kuroi
Regular
Posts: 129
Joined: Fri Jun 29, 2007 10:50 am
Location: Albuquerque, New Mexico, USA
Contact:

the effect of ATL on Renpy customisation

#1 Post by kuroi »

I have been working a lot on making revisions to the Kuroi Games manga engine and it got me thinking about the ATL. It seems that while the Renpy script system works really well for most games, the majority of the more heavy modding of Renpy to create things such as battle engines, manga systems (like mine *shameless plug*), ect... must be doing using python. However, since there is no way to create ATL code programatically, I fear that in the long run the more python heavy projects may lose out on some of the more shiney features enabled by the ATL.

I'm not ready to say that this is a problem but I'd like to hear other people's thoughts on the manner. Perhaps it's not an issue at all and there are some very inventive ways to use the Transform function which would enable it to do everything that the ATL does or something like that.

Anyway, does anyone else have thoughts about this?
President, Planner, and Programmer for Kuroi Games!

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: the effect of ATL on Renpy customisation

#2 Post by PyTom »

Anything you can do with ATL, you can do with Transforms, using an appropriate Python function. This is 100% guaranteed, as ATL actually uses Transform internally to do its thing.

Now, it might be easier to do something in ATL than in Python. But that's the whole point of ATL, making this sort of thing simpler and more flexible. I'll also note that ATL transforms can take parameters. It's hard to think of code-generated ATL that wouldn't conform to a fairly strict template, such that one can get away with parameterized ATL.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Mihara
Regular
Posts: 119
Joined: Thu Mar 11, 2010 2:52 pm
Contact:

Re: the effect of ATL on Renpy customisation

#3 Post by Mihara »

PyTom wrote:I'll also note that ATL transforms can take parameters.
...and lint complains about them, thinking transforms with parameters are actually functions it can't evaluate. :(

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: the effect of ATL on Renpy customisation

#4 Post by Jake »

kuroi wrote: Perhaps it's not an issue at all and there are some very inventive ways to use the Transform function which would enable it to do everything that the ATL does or something like that.
Since it hasn't actually been mentioned yet: yes, you use the 'function' parameter of the Transform object to do pretty much all the cool functionality you can write in ATL statements.

If you want to have a thing which fades in over the course of the first second, and then moves to the right from xpos=200px to 400px over the course of the next second, you could write your transform function to look something like (off the top of my head) this:

Code: Select all

  def myTransformFunction(tran, st, at):
    if (st >= 0 and st <= 1):
      tran.alpha = st
      return 0
    elif (st > 1 and st <= 2):
      tran.xpos = 200 + ( (st - 1) * 200)
      return 0
    return 999999

  myTransform = Transform(xpos=200, function=myTransformFunction)
which would be the equivalent of ATL like:

Code: Select all

  transform myTransform:
    xpos 200
    alpha 0.0
    linear 1 alpha 1.0
    linear 1 xpos 400
If you want to do something 'on show', then do it when the at is 0.0; if you want to do something 'on replace', do it when the st is 0.0 and the at is not (presuming I remember which way around those two are); if you want to do something 'on hide', do it when 'hide_request' is True, and set hide_response to False until your thing has finished. Return 0 from your function if you're doing something you want to happen in a smooth manner.
PyTom wrote:Anything you can do with ATL, you can do with Transforms, using an appropriate Python function. This is 100% guaranteed, as ATL actually uses Transform internally to do its thing.
The problem here is that the documentation doesn't really make this particularly clear, and in fact includes statements like "There is no way to create ATL code programatically", which gives people the opposite impression. (I know it's not what you meant, but it's how a lot of people are likely to read it, IMO.)

Unless I'm missing something quite drastic, the only way to do most of the cool stuff with Transform is by implementing your own transform functions, but the documentation doesn't really make it clear how to use that facility.

- When exactly will the transform's function will be called? Will it definitely be called with an st of 0 when the Displayable is first shown? Will it definitely be called when the Displayable is first hidden and have a chance to delay the hide? We presume that the answer to these questions must be 'yes' only if we've already been told that the Transform method can do everything ATL can, but the docs only say 'before the Transform is rendered', which doesn't even account for the 'hide' case at all.
- How does one then subsequently get their Transform hidden again? Is it just by setting hide_request to True and hide_response to True? Can one do this even if no hide statement or call to renpy.hide was made, to remove an item from the scene list?
How should one return from the transform function if the transform is effectively finished, if '0' makes it render again next frame? I used a very high number in the example above, but maybe -1 would be more appropriate? It doesn't say.
- How should the Transform's 'child' member be used? Is it possible to put another Transform in there and if so, what happens? I know the answers to these last two questions only because I was curious and tried it, but the correct answer isn't even implied in the docs for the second one of those.

If the answers to any of those questions are actually written in the docs, I didn't see them.

Something I still don't know about Transforms: when someone writes a complex ATL transform involving show and hide events and timed property modifications and so on, do you have a stock of plug-together functions that you construct and pass in, or do you do code generation to create a function on the fly which fulfils their requirements? I expect it's probably the latter, because after a bit of flexibility it possibly becomes the simpler thing to write, but if it's the former, is there any reason other people shouldn't use the same functions for their programmatically-generated Transforms?



And presuming you're using code generation or some other internal trick, it's still not really that plausible to programmatically-generate transforms, because you can't take parameters or user input or situational state and generate a transform that does cool ATL stuff dependent on that, because you have to write a function which does exactly what you want. (Well, you could get away with it by using a lot of generic methods and some currying, I expect, but that's a long way beyond most amateur programmers' abilities.)
Server error: user 'Jake' not found

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: the effect of ATL on Renpy customisation

#5 Post by PyTom »

Jake wrote: - When exactly will the transform's function will be called? Will it definitely be called with an st of 0 when the Displayable is first shown? Will it definitely be called when the Displayable is first hidden and have a chance to delay the hide? We presume that the answer to these questions must be 'yes' only if we've already been told that the Transform method can do everything ATL can, but the docs only say 'before the Transform is rendered', which doesn't even account for the 'hide' case at all.
Yes, in both cases. In the latter, there's the hide_request/hide_response method. (This has been augmented in 6.11 to have a replaced_request/replaced_response pair, as well.)
- How does one then subsequently get their Transform hidden again? Is it just by setting hide_request to True and hide_response to True? Can one do this even if no hide statement or call to renpy.hide was made, to remove an item from the scene list?
Yes. Setting them to True will cause the Transform to stop rendering, and it will be automatically removed at the end of the interaction.
How should one return from the transform function if the transform is effectively finished, if '0' makes it render again next frame? I used a very high number in the example above, but maybe -1 would be more appropriate? It doesn't say.
None.
- How should the Transform's 'child' member be used? Is it possible to put another Transform in there and if so, what happens? I know the answers to these last two questions only because I was curious and tried it, but the correct answer isn't even implied in the docs for the second one of those.
It actually shouldn't be used directly, but set_child should be used.
If the answers to any of those questions are actually written in the docs, I didn't see them.
I am in the process of updating the docs, and hopefully I'll get this written up correctly. I do find this sort of feedback valuable - even if I don't get to it right away, it does slowly improve Ren'Py over time.
Something I still don't know about Transforms: when someone writes a complex ATL transform involving show and hide events and timed property modifications and so on, do you have a stock of plug-together functions that you construct and pass in, or do you do code generation to create a function on the fly which fulfils their requirements? I expect it's probably the latter, because after a bit of flexibility it possibly becomes the simpler thing to write, but if it's the former, is there any reason other people shouldn't use the same functions for their programmatically-generated Transforms?
ATL actually works the same way as Ren'Py. We build up a syntax tree, and then traverse that syntax tree in order to evaluate the code. There's some fun stuff when it comes to the way that state is preserved between transforms, but it's fundamentally just a syntax tree.

I don't really want to document the details of the syntax tree, because I consider them to be an implementation detail rather than an API. I don't want to be stuck supporting the particular details into the future. (At some point, I may actually move to code-generation.)
And presuming you're using code generation or some other internal trick, it's still not really that plausible to programmatically-generate transforms, because you can't take parameters or user input or situational state and generate a transform that does cool ATL stuff dependent on that, because you have to write a function which does exactly what you want. (Well, you could get away with it by using a lot of generic methods and some currying, I expect, but that's a long way beyond most amateur programmers' abilities.)
One good way to do this is a Python object with a call method. I'm still not sure what generated-ATL can do that parameterized-ATL can't, however. If there was something, I'd consider extending ATL to address it.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: the effect of ATL on Renpy customisation

#6 Post by Jake »

PyTom wrote: It actually shouldn't be used directly, but set_child should be used.
Sorry, I used the wrong word - I actually meant the 'child' parameter to the initialiser. (Which one presumes is meant to be used, since it's a parameter to the initializer... ;-)
PyTom wrote: I'm still not sure what generated-ATL can do that parameterized-ATL can't, however. If there was something, I'd consider extending ATL to address it.
"Be dynamically generated from code" is the main thing, honestly. For example, in the battle engine I'm writing, I want to draw a guy moving from one square to another square over the actual square-to-square route taken... and at each step, he might change to a new animation (to show him walking in the new direction) which possibly-but-not-guaranteed has a transitional animation to show him rotating or whatever.

If I knew exactly the path which character is going to take with what pan offset before runtime, I could easily encode this in an ATL transformation, leaving the main Ren'Py thread free to go off and do other things while he's walking. I could theoretically write code which performs this complex arrangement of movements and sprite changes in a Transform function at runtime, but I don't think I could do it with an ATL statement since I don't think there's any way I could encode the route the guy's taking as a parameter and actually make use of it. And honestly, I don't think it's worth trying to extend ATL to include stuff like that, you'd just end up having to create another turing-complete language for a tiny fraction of potential uses.

(And as it happens, I want to break the movement down into steps anyway, so other Fighters have the opportunity to interrupt a guy's movement with reaction-fire or whatever, so I'm happy enough to be doing it step-by-step in code anyway.)
Server error: user 'Jake' not found

Post Reply

Who is online

Users browsing this forum: No registered users