Possible to create transforms mid code?

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
Evildumdum
Regular
Posts: 191
Joined: Sun Jan 18, 2015 8:49 am
Projects: ApoclypseZ
Contact:

Possible to create transforms mid code?

#1 Post by Evildumdum »

So i have a need to make transforms that have an numerous changes of direction. I need to be able to create transforms to show movement paths, but since the route taken is not decided until the start point and end point of any given path is determined it is impossible to define a transform in an init block that is enough to cover all eventualities. The path's length can vary and can twist and turn as needed to bypass obstacles. I'm using a method of multiple small pre defined transforms to move along these paths, but it is jerky and inefficient.

I've had a stab at Aenakume's Bezier Motion Code, but it's not really usable in my situation. I was wondering if there was a way to define transforms on the fly in the same way you can define global variables mid code, or perhaps a way of structuring a transform to accept more variables. The main issue i'm hitting is that for loops are not supported in transforms, but there might be a workaround i'm not aware of (I hope).

If anyone has a good knowledge of transforms and might be able to help i'd really appreciate it.
"If at first you don't succeed, try hitting it with a shoe."

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Possible to create transforms mid code?

#2 Post by xela »

Code: Select all

transform my_atl_instructions(*args, **kwargs):
    # ...
You should be able to setup max amount of movements allowed and if there is less than that max amount, provide time of 0 and final moves will be ignored. Otherwise, you can use a function to control what the displayable does (Transform class takes a func, atl as well iirc).
Like what we're doing? Support us at:
Image

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Possible to create transforms mid code?

#3 Post by Remix »

Bezier is not 'easily' useful for paths that generally want to actually go through each point, you'd need to calculate the Bezier control points and then calculate a path based upon those... messy and umm still Bezier.
A much nicer option, in my opinion, is Cat-mull Rom pathing though that uses matrix multiplication and most Python examples import numpy which is a C based math library and hence would not sit well as a Ren'py import... I think it could still be done with simpler math though and might still be worth looking at.
You could smooth your 'turn' points by writing your own algorithm that uses a set radius circle to arc at each point then calculates an arc from each logical intersection to the centre of each path segment... easiest math, fastest compute, maybe most work though
Knots in Ren'py... if you can understand what each co-ordinate relates to in the movement... might also be an option

As xela says, you are likely looking at passing parameters into a set ATL transform (which will get messy as atl definitions do not play well with more than just simple coding logic. The alternative is function...
Pseudo code

Code: Select all

init python:

    # basic move in a circle sort of thing... 
    # no actual path logic
    def move_ellipse(trans, st, at):
        rad = st / 10 * math.pi * 2
        trans.xalign = float(math.sin(rad)) / 4 + 0.5
        trans.yalign = float(math.cos(rad)) / 4 + 0.5
        return 0.02 # 50fps

    # presuming we had a function elsewhere that returned
    # a (x, y) co-ordinate tuple based upon time we could
    # use something like this
    def move_along_precalculated_path(trans, st, at):
        trans.xalign, trans.yalign = get_coords_for_time( st )
        return 0.02 # 50fps

label start:
    # $ girl = AnimatedSprite("girl", girl_sprites.get_sprite_map(), image="girl_tag" )
    show expression (girl) as tara:
        function move_ellipse
As you can see, the transform functions cannot be passed extra information, so cannot themselves calculate the path unless all the outside data is globalized. The path points calculation would in most cases be best done outside the atl function and called for.

On an aside: You should note, Bezier, Cat-mull Rom and probably Knot based paths are all non equidistant points algorithms which basically means if you are moving along them with a linear time step you will be seen to be moving at a non linear speed.

I am in the midst of finishing an events controller at the moment. Perhaps afterwards I might revisit the Cat-mull Rom stuff and get a few sprites walking around
Frameworks & Scriptlets:

User avatar
Evildumdum
Regular
Posts: 191
Joined: Sun Jan 18, 2015 8:49 am
Projects: ApoclypseZ
Contact:

Re: Possible to create transforms mid code?

#4 Post by Evildumdum »

Both brilliant pieces of advice. That function looks worth digging into in earnest. In terms of the way i structure the movement, its based on a grid and the path is a list of grid co-ordinates.
"If at first you don't succeed, try hitting it with a shoe."

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Possible to create transforms mid code?

#5 Post by Remix »

To help you along:

Any ATL function is always passed 3 parameters;
trans -> the transform object - you can directly alter positions (trans.xpos, ypos, align etc) of that or even delve down to the child displayable
st -> the important one - this is the time in seconds since the function was first called - it drops back to 0.0 if called fresh again
at -> rarely worth using - the seconds since the displayable first appeared

The function can return;
A float -> seconds until next repeat is called -> such as 0.04 (25 fps) or 0.0 (as soon as possible/next screen draw call)
None -> function has finished, no more repeat, pass control back to calling line

If/when I do get back to the Cat-mull stuff I would personally implement a class or function that built a list of x,y (or even x,y,z) co-ordinates that were equidistant apart along the calculated path (or segments there-of). Within that an iterator or method would be called with a time (0.0 to 0.1) that could be pre-warped if desired and return a tuple representing the x,y(,z) relating to that time. This should allow a semblance of linear path speed to be seen on the screen, would allow warpers to work correctly where desired (either as full path or just segment) and allow segments to define their own friction/speed. . . . Once I finish this Event system that is...
Frameworks & Scriptlets:

Post Reply

Who is online

Users browsing this forum: Semrush [Bot]